Skip to content

Commit 7088bfd

Browse files
authored
chore: adds test that included dkg key generation and signing all in one test (#5324)
1 parent a547849 commit 7088bfd

File tree

1 file changed

+195
-2
lines changed

1 file changed

+195
-2
lines changed

ironfish-rust/src/transaction/tests.rs

Lines changed: 195 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ use std::collections::{BTreeMap, HashMap};
66

77
#[cfg(test)]
88
use super::internal_batch_verify_transactions;
9-
109
use super::{ProposedTransaction, Transaction, TRANSACTION_PUBLIC_KEY_SIZE};
11-
10+
use crate::frost_utils::account_keys::derive_account_keys;
1211
use crate::test_util::create_multisig_identities;
1312
use crate::transaction::tests::split_spender_key::split_spender_key;
1413
use crate::{
@@ -27,6 +26,8 @@ use crate::{
2726
};
2827
use ff::Field;
2928
use group::GroupEncoding;
29+
use ironfish_frost::dkg::{round1 as round1_dkg, round2 as round2_dkg, round3 as round3_dkg};
30+
use ironfish_frost::participant::Secret;
3031
use ironfish_frost::{
3132
frost::{round2, round2::SignatureShare, Identifier, Randomizer},
3233
nonces::deterministic_signing_nonces,
@@ -915,3 +916,195 @@ fn test_add_signature_by_building_transaction() {
915916

916917
verify_transaction(&signed).expect("should be able to verify transaction");
917918
}
919+
920+
#[test]
921+
fn test_dkg_signing() {
922+
let secret1 = Secret::random(thread_rng());
923+
let secret2 = Secret::random(thread_rng());
924+
let secret3 = Secret::random(thread_rng());
925+
let identity1 = secret1.to_identity();
926+
let identity2 = secret2.to_identity();
927+
let identity3 = secret3.to_identity();
928+
let identities = &[identity1.clone(), identity2.clone(), identity3.clone()];
929+
930+
let (round1_secret_package_1, package1) = round1_dkg::round1(
931+
&identity1,
932+
2,
933+
[&identity1, &identity2, &identity3],
934+
thread_rng(),
935+
)
936+
.expect("round 1 failed");
937+
938+
let (round1_secret_package_2, package2) = round1_dkg::round1(
939+
&identity2,
940+
2,
941+
[&identity1, &identity2, &identity3],
942+
thread_rng(),
943+
)
944+
.expect("round 1 failed");
945+
946+
let (round1_secret_package_3, package3) = round1_dkg::round1(
947+
&identity3,
948+
2,
949+
[&identity1, &identity2, &identity3],
950+
thread_rng(),
951+
)
952+
.expect("round 1 failed");
953+
954+
let (encrypted_secret_package_1, round2_public_packages_1) = round2_dkg::round2(
955+
&secret1,
956+
&round1_secret_package_1,
957+
[&package1, &package2, &package3],
958+
thread_rng(),
959+
)
960+
.expect("round 2 failed");
961+
962+
let (encrypted_secret_package_2, round2_public_packages_2) = round2_dkg::round2(
963+
&secret2,
964+
&round1_secret_package_2,
965+
[&package1, &package2, &package3],
966+
thread_rng(),
967+
)
968+
.expect("round 2 failed");
969+
970+
let (encrypted_secret_package_3, round2_public_packages_3) = round2_dkg::round2(
971+
&secret3,
972+
&round1_secret_package_3,
973+
[&package1, &package2, &package3],
974+
thread_rng(),
975+
)
976+
.expect("round 2 failed");
977+
978+
let (key_package_1, public_key_package, group_secret_key) = round3_dkg::round3(
979+
&secret1,
980+
&encrypted_secret_package_1,
981+
[&package1, &package2, &package3],
982+
[&round2_public_packages_2, &round2_public_packages_3],
983+
)
984+
.expect("round 3 failed");
985+
986+
let (key_package_2, _, _) = round3_dkg::round3(
987+
&secret2,
988+
&encrypted_secret_package_2,
989+
[&package1, &package2, &package3],
990+
[&round2_public_packages_1, &round2_public_packages_3],
991+
)
992+
.expect("round 3 failed");
993+
994+
let (key_package_3, _, _) = round3_dkg::round3(
995+
&secret3,
996+
&encrypted_secret_package_3,
997+
[&package1, &package2, &package3],
998+
[&round2_public_packages_1, &round2_public_packages_2],
999+
)
1000+
.expect("round 3 failed");
1001+
1002+
let account_keys = derive_account_keys(public_key_package.verifying_key(), &group_secret_key);
1003+
let public_address = account_keys.public_address;
1004+
1005+
// create raw/proposed transaction
1006+
let in_note = Note::new(public_address, 42, "", NATIVE_ASSET, public_address);
1007+
let out_note = Note::new(public_address, 40, "", NATIVE_ASSET, public_address);
1008+
let asset = Asset::new(public_address, "Testcoin", "A really cool coin")
1009+
.expect("should be able to create an asset");
1010+
let value = 5;
1011+
let mint_out_note = Note::new(public_address, value, "", *asset.id(), public_address);
1012+
let witness = make_fake_witness(&in_note);
1013+
1014+
let mut transaction = ProposedTransaction::new(TransactionVersion::latest());
1015+
transaction
1016+
.add_spend(in_note, &witness)
1017+
.expect("add spend to transaction");
1018+
assert_eq!(transaction.spends.len(), 1);
1019+
transaction
1020+
.add_output(out_note)
1021+
.expect("add output to transaction");
1022+
assert_eq!(transaction.outputs.len(), 1);
1023+
transaction
1024+
.add_mint(asset, value)
1025+
.expect("add mint to transaction");
1026+
transaction
1027+
.add_output(mint_out_note)
1028+
.expect("add mint output to transaction");
1029+
1030+
let intended_fee = 1;
1031+
transaction
1032+
.add_change_notes(Some(public_address), public_address, intended_fee)
1033+
.expect("should be able to add change notes");
1034+
1035+
// build UnsignedTransaction without signing
1036+
let mut unsigned_transaction = transaction
1037+
.build(
1038+
account_keys.proof_authorizing_key,
1039+
account_keys.view_key,
1040+
account_keys.outgoing_viewing_key,
1041+
intended_fee,
1042+
Some(account_keys.public_address),
1043+
)
1044+
.expect("should be able to build unsigned transaction");
1045+
1046+
let transaction_hash = unsigned_transaction
1047+
.transaction_signature_hash()
1048+
.expect("should be able to compute transaction hash");
1049+
1050+
let mut commitments = HashMap::new();
1051+
1052+
// simulate signing
1053+
// commitment generation
1054+
let identity_keypackages = [
1055+
(identity1, key_package_1),
1056+
(identity2, key_package_2),
1057+
(identity3, key_package_3),
1058+
];
1059+
for (identity, key_package) in identity_keypackages.iter() {
1060+
let nonces = deterministic_signing_nonces(
1061+
key_package.signing_share(),
1062+
&transaction_hash,
1063+
identities,
1064+
);
1065+
commitments.insert(identity.clone(), (&nonces).into());
1066+
}
1067+
1068+
let signing_package = unsigned_transaction
1069+
.signing_package(commitments)
1070+
.expect("should be able to create signing package");
1071+
1072+
// simulate round 2
1073+
let mut signature_shares: BTreeMap<Identifier, SignatureShare> = BTreeMap::new();
1074+
let randomizer =
1075+
Randomizer::deserialize(&unsigned_transaction.public_key_randomness.to_bytes())
1076+
.expect("should be able to deserialize randomizer");
1077+
1078+
for (identity, key_package) in identity_keypackages.iter() {
1079+
let nonces = deterministic_signing_nonces(
1080+
key_package.signing_share(),
1081+
&transaction_hash,
1082+
identities,
1083+
);
1084+
let signature_share = round2::sign(
1085+
&signing_package.frost_signing_package,
1086+
&nonces,
1087+
key_package,
1088+
randomizer,
1089+
)
1090+
.expect("should be able to create signature share");
1091+
signature_shares.insert(identity.to_frost_identifier(), signature_share);
1092+
}
1093+
1094+
// coordinator creates signed transaction
1095+
let signed_transaction = unsigned_transaction
1096+
.aggregate_signature_shares(
1097+
&public_key_package,
1098+
&signing_package.frost_signing_package,
1099+
signature_shares,
1100+
)
1101+
.expect("should be able to sign transaction");
1102+
1103+
assert_eq!(signed_transaction.spends.len(), 1);
1104+
assert_eq!(signed_transaction.outputs.len(), 3);
1105+
assert_eq!(signed_transaction.mints.len(), 1);
1106+
assert_eq!(signed_transaction.burns.len(), 0);
1107+
1108+
// verify transaction
1109+
verify_transaction(&signed_transaction).expect("should be able to verify transaction");
1110+
}

0 commit comments

Comments
 (0)