Skip to content

Commit eb6ac25

Browse files
committed
add tests to vess over reshares
1 parent c2b735a commit eb6ac25

File tree

1 file changed

+197
-11
lines changed

1 file changed

+197
-11
lines changed

timeboost-crypto/src/vess.rs

Lines changed: 197 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,9 @@ impl From<spongefish::DomainSeparatorMismatch> for VessError {
860860
#[cfg(test)]
861861
mod tests {
862862
use super::*;
863+
use crate::traits::dkg::KeyResharing;
863864
use ark_bls12_381::{Fr, G1Projective};
865+
use ark_ec::PrimeGroup;
864866
use ark_std::{
865867
UniformRand,
866868
rand::{SeedableRng, rngs::StdRng},
@@ -872,22 +874,25 @@ mod tests {
872874

873875
type Vss = FeldmanVss<G1Projective>;
874876

877+
/// Helper function to create a test committee with specified parameters
878+
fn create_test_committee(epoch: u64, size: usize) -> multisig::Committee {
879+
let keypairs: Vec<multisig::Keypair> =
880+
(0..size).map(|_| multisig::Keypair::generate()).collect();
881+
multisig::Committee::new(
882+
epoch,
883+
keypairs
884+
.iter()
885+
.enumerate()
886+
.map(|(i, kp)| (i as u8, kp.public_key())),
887+
)
888+
}
889+
875890
fn test_vess_correctness_helper(vess: ShoupVess<G1Projective>) {
876891
let rng = &mut StdRng::seed_from_u64(0);
877892
let secret = Fr::rand(rng);
878893

879894
// Create a test committee
880-
let committee_size = 13;
881-
let keypairs: Vec<multisig::Keypair> = (0..committee_size)
882-
.map(|_| multisig::Keypair::generate())
883-
.collect();
884-
let committee = multisig::Committee::new(
885-
0u64,
886-
keypairs
887-
.iter()
888-
.enumerate()
889-
.map(|(i, kp)| (i as u8, kp.public_key())),
890-
);
895+
let committee = create_test_committee(0, 13);
891896
let n = committee.size().get();
892897

893898
let recv_sks: Vec<mre::DecryptionKey<G1Projective>> =
@@ -945,4 +950,185 @@ mod tests {
945950
assert!(subsets.insert(subset));
946951
}
947952
}
953+
954+
/// Test VESS resharing functionality with comprehensive verification
955+
#[test]
956+
fn test_vess_resharing_correctness() {
957+
test_vess_resharing_helper(ShoupVess::new_fast());
958+
test_vess_resharing_helper(ShoupVess::new_short());
959+
}
960+
961+
/// Helper function for testing VESS resharing with different parameter sets
962+
fn test_vess_resharing_helper(vess: ShoupVess<G1Projective>) {
963+
let rng = &mut StdRng::seed_from_u64(42);
964+
965+
// Test multiple scenarios with different committee sizes
966+
let test_scenarios = vec![
967+
(7, 7), // Same committee size
968+
(5, 8), // Expanding committee
969+
(9, 6), // Shrinking committee
970+
(6, 7), // Mixed changes
971+
];
972+
973+
for (old_n, new_n) in test_scenarios {
974+
run_vess_resharing_scenario(&vess, old_n, new_n, rng);
975+
}
976+
}
977+
978+
/// Core test logic for a single VESS resharing scenario
979+
fn run_vess_resharing_scenario(
980+
vess: &ShoupVess<G1Projective>,
981+
old_n: usize,
982+
new_n: usize,
983+
rng: &mut StdRng,
984+
) {
985+
// Step 1: Set up old committee and perform initial VSS
986+
let old_committee = create_test_committee(0, old_n);
987+
let secret = Fr::rand(rng);
988+
let old_vss_pp = FeldmanVssPublicParam::from(&old_committee);
989+
let (old_shares, old_commitment) = Vss::share(&old_vss_pp, rng, secret);
990+
991+
// Step 2: Set up new committee
992+
let new_committee = create_test_committee(1, new_n);
993+
let new_vss_pp = FeldmanVssPublicParam::from(&new_committee);
994+
995+
// Generate encryption keys for new committee members
996+
let new_recv_sks: Vec<mre::DecryptionKey<G1Projective>> =
997+
repeat_with(|| mre::DecryptionKey::rand(rng))
998+
.take(new_n)
999+
.collect();
1000+
let new_recv_pks: BTreeMap<usize, mre::EncryptionKey<G1Projective>> = new_recv_sks
1001+
.iter()
1002+
.enumerate()
1003+
.map(|(i, sk)| (i, mre::EncryptionKey::from(sk)))
1004+
.collect();
1005+
let new_labeled_sks: Vec<LabeledDecryptionKey<G1Projective>> = new_recv_sks
1006+
.into_iter()
1007+
.enumerate()
1008+
.map(|(i, sk)| sk.label(i))
1009+
.collect();
1010+
1011+
// Step 3: Perform resharing for each old committee member
1012+
let aad = b"reshare_test_associated_data";
1013+
let mut reshare_dealings = Vec::new();
1014+
1015+
// Each old committee member creates encrypted reshares
1016+
for (sender_idx, old_share) in old_shares.iter().enumerate() {
1017+
// Derive the public share for this sender from the old committee
1018+
let sender_pub_share = G1Projective::generator() * old_shares[sender_idx];
1019+
1020+
// Create VESS encrypted reshares using the public encrypt_reshares API
1021+
let (reshare_ct, reshare_comm) = vess
1022+
.encrypt_reshares(&new_committee, new_recv_pks.values(), *old_share, aad)
1023+
.expect("Reshare encryption should succeed");
1024+
1025+
// Step 4: Verify the encrypted reshares
1026+
assert!(
1027+
vess.verify_reshares(
1028+
&new_committee,
1029+
new_recv_pks.values(),
1030+
&reshare_ct,
1031+
&reshare_comm,
1032+
aad,
1033+
sender_pub_share,
1034+
)
1035+
.is_ok(),
1036+
"Reshare verification should succeed for sender {sender_idx}"
1037+
);
1038+
1039+
reshare_dealings.push((reshare_ct, reshare_comm, sender_pub_share));
1040+
}
1041+
1042+
// Step 5: Decrypt reshares and verify they pass FeldmanVss::verify_reshare
1043+
for (new_member_idx, new_labeled_sk) in new_labeled_sks.iter().enumerate() {
1044+
// Decrypt reshares from each old committee member
1045+
for (sender_idx, (reshare_ct, reshare_comm, sender_pub_share)) in
1046+
reshare_dealings.iter().enumerate()
1047+
{
1048+
let decrypted_reshare = vess
1049+
.decrypt_reshare(
1050+
&new_committee,
1051+
new_labeled_sk,
1052+
reshare_ct,
1053+
aad,
1054+
*sender_pub_share,
1055+
)
1056+
.expect(
1057+
"Decrypt should succeed, sender: {sender_idx}, receiver: {new_member_idx}",
1058+
);
1059+
1060+
assert!(
1061+
Vss::verify_reshare(
1062+
&old_vss_pp,
1063+
&new_vss_pp,
1064+
sender_idx,
1065+
new_member_idx,
1066+
&old_commitment,
1067+
reshare_comm,
1068+
&decrypted_reshare,
1069+
)
1070+
.is_ok(),
1071+
"Verification should pass, sender: {sender_idx}, receiver: {new_member_idx}"
1072+
);
1073+
}
1074+
}
1075+
}
1076+
1077+
/// Test invalid scenarios that should fail verification
1078+
#[test]
1079+
fn test_vess_resharing_basic_soundness() {
1080+
let vess = ShoupVess::new_fast();
1081+
let rng = &mut StdRng::seed_from_u64(456);
1082+
1083+
// Set up committees
1084+
let old_committee = create_test_committee(0, 3);
1085+
let new_committee = create_test_committee(1, 4);
1086+
1087+
let secret = Fr::rand(rng);
1088+
let old_vss_pp = FeldmanVssPublicParam::from(&old_committee);
1089+
let (old_shares, old_commitment) = Vss::share(&old_vss_pp, rng, secret);
1090+
1091+
// Create recipient keys
1092+
let new_recv_pks: Vec<mre::EncryptionKey<G1Projective>> = (0..4)
1093+
.map(|_| mre::EncryptionKey::from(&mre::DecryptionKey::rand(rng)))
1094+
.collect();
1095+
1096+
let sender_pub_share = Vss::derive_public_share_unchecked(0, &old_commitment);
1097+
let aad = b"test_failure_cases";
1098+
1099+
// Create valid encrypted reshares
1100+
let (reshare_ct, reshare_comm) = vess
1101+
.encrypt_reshares(&new_committee, &new_recv_pks, old_shares[0], aad)
1102+
.unwrap();
1103+
1104+
// Test 1: Wrong public share should fail verification
1105+
let wrong_pub_share = G1Projective::generator() * Fr::rand(rng);
1106+
assert!(
1107+
vess.verify_reshares(
1108+
&new_committee,
1109+
&new_recv_pks,
1110+
&reshare_ct,
1111+
&reshare_comm,
1112+
aad,
1113+
wrong_pub_share,
1114+
)
1115+
.is_err(),
1116+
"Verification with wrong public share should fail"
1117+
);
1118+
1119+
// Test 2: Wrong AAD should fail verification
1120+
let wrong_aad = b"wrong_associated_data";
1121+
assert!(
1122+
vess.verify_reshares(
1123+
&new_committee,
1124+
&new_recv_pks,
1125+
&reshare_ct,
1126+
&reshare_comm,
1127+
wrong_aad,
1128+
sender_pub_share,
1129+
)
1130+
.is_err(),
1131+
"Verification with wrong AAD should fail"
1132+
);
1133+
}
9481134
}

0 commit comments

Comments
 (0)