Skip to content

Commit ada0d86

Browse files
authored
Improve dkg_verification docs (#6)
* docs: add GitHub DKG implementations * Update documentation * Simplify public commitments * Update the readme * Update the readme * Add verification unit test for edge cases * Add unit tests
1 parent 46a2df6 commit ada0d86

File tree

12 files changed

+378
-81
lines changed

12 files changed

+378
-81
lines changed

crates/bad_encrypted_share_prove/src/main.rs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -311,18 +311,23 @@ where
311311
);
312312
}
313313

314-
let mut keys = data.receiver_base_pubkeys.clone();
315-
keys.sort();
316-
317-
if Setup::DkgSecretKey::from_bytes(&data.receiver_encr_seckey)
318-
.expect("Invalid seckey")
319-
.to_public_key()
320-
.to_bytes()
321-
!= keys[keys.len() - 1]
322-
{
323-
panic!("Invalid seckey");
314+
let mut ordered_receiver_base_pubkeys = data.receiver_base_pubkeys.clone();
315+
ordered_receiver_base_pubkeys.sort();
316+
317+
let receiver_sk =
318+
Setup::DkgSecretKey::from_bytes(&data.receiver_encr_seckey).expect("Invalid seckey");
319+
let receiver_pk_bytes = receiver_sk.to_public_key().to_bytes();
320+
if receiver_pk_bytes != ordered_receiver_base_pubkeys[ordered_receiver_base_pubkeys.len() - 1] {
321+
panic!("Invalid encryption key");
324322
};
325323

324+
let mut ordered_sender_base_pubkeys = data.sender_base_pubkeys.clone();
325+
ordered_sender_base_pubkeys.sort();
326+
if data.sender_encr_pubkey != ordered_sender_base_pubkeys[ordered_sender_base_pubkeys.len() - 1]
327+
{
328+
panic!("Invalid encryption key");
329+
}
330+
326331
if data.base_hashes.len() != data.settings.n as usize {
327332
panic!("The number of verification hashes does not match the number of keys\n");
328333
}
@@ -346,15 +351,19 @@ where
346351
decrypted,
347352
data.settings,
348353
data.sender_base_pubkeys,
349-
data.base_hashes,
354+
data.base_hashes.clone(),
350355
receiver_commitment_hash,
351356
sender_commitment_hash,
352357
) {
353358
Ok(data) => data,
354359
Err(e) => {
355360
println!("Error: {}", e);
356-
sp1_zkvm::io::commit(&sender_commitment_hash);
357-
sp1_zkvm::io::commit(&receiver_commitment_hash);
361+
for h in data.base_hashes.iter() {
362+
println!("Verification hash: {}, {}", h, e);
363+
sp1_zkvm::io::commit(h);
364+
}
365+
sp1_zkvm::io::commit(&receiver_pk_bytes);
366+
sp1_zkvm::io::commit(&data.sender_encr_pubkey);
358367
sp1_zkvm::io::commit(&data.encrypted_message);
359368
return;
360369
}
@@ -383,9 +392,13 @@ where
383392
receiver_commitment_hash,
384393
);
385394

386-
sp1_zkvm::io::commit(&sender_commitment_hash);
387-
sp1_zkvm::io::commit(&receiver_commitment_hash);
388-
sp1_zkvm::io::commit(&encrypted_bytes);
395+
for h in data.base_hashes.iter() {
396+
println!("Verification hash: {}, {}", h, e);
397+
sp1_zkvm::io::commit(h);
398+
}
399+
sp1_zkvm::io::commit(&receiver_pk_bytes);
400+
sp1_zkvm::io::commit(&data.sender_encr_pubkey);
401+
sp1_zkvm::io::commit(&data.encrypted_message);
389402
}
390403
}
391404
panic!("The seed exchange commitment is valid");

crates/bad_parial_key_prove/src/main.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,14 @@ where
3030
VerificationErrors::SlashableError(e) => {
3131
for h in data.generations.iter() {
3232
println!("Verification hash: {}, {}", h.base_hash.to_hex(), e);
33-
sp1_zkvm::io::commit(h.base_hash.as_ref());
33+
sp1_zkvm::io::commit(&h.base_hash);
3434
}
3535

3636
println!(
3737
"Perpetrator public key: {}",
3838
data.bad_partial.commitment.pubkey.to_hex()
3939
);
40-
for byte in data.bad_partial.commitment.pubkey.as_arr().iter() {
41-
sp1_zkvm::io::commit(&byte);
42-
}
40+
sp1_zkvm::io::commit(&data.bad_partial.commitment.pubkey);
4341
return;
4442
}
4543
VerificationErrors::UnslashableError(e) => {

crates/bad_share_exchange_prove/src/main.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,15 @@ where
5858
println!("Slashable error seed exchange commitment: {}", err);
5959

6060
for h in data.verification_hashes.iter() {
61-
println!("Verification hash: {}", h.to_hex());
62-
sp1_zkvm::io::commit(h.as_ref());
61+
println!("Verification hash: {}", h);
62+
sp1_zkvm::io::commit(&h);
6363
}
6464

6565
println!(
6666
"Perpetrator public key: {}",
67-
data.seeds_exchange_commitment.commitment.pubkey.to_hex()
67+
data.seeds_exchange_commitment.commitment.pubkey
6868
);
69-
for byte in data.seeds_exchange_commitment.commitment.pubkey.as_arr() {
70-
sp1_zkvm::io::commit(&byte);
71-
}
72-
69+
sp1_zkvm::io::commit(&data.seeds_exchange_commitment.commitment.pubkey);
7370
return;
7471
}
7572
VerificationErrors::UnslashableError(err) => {

crates/dkg/src/crypto/bls_common.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,69 @@ pub fn to_g1_affine(pubkey: &BLSPubkeyRaw) -> G1Affine {
114114
pub fn to_g1_projection(pubkey: &BLSPubkeyRaw) -> G1Projective {
115115
G1Projective::from(to_g1_affine(pubkey))
116116
}
117+
118+
#[cfg(test)]
119+
mod tests {
120+
use super::*;
121+
122+
#[test]
123+
fn test_hash_message_to_g2_deterministic() {
124+
let msg = b"hello";
125+
let p1 = G2Affine::from(hash_message_to_g2(msg));
126+
let p2 = G2Affine::from(hash_message_to_g2(msg));
127+
assert_eq!(p1, p2);
128+
129+
let p3 = G2Affine::from(hash_message_to_g2(b"world"));
130+
assert_ne!(p1, p3);
131+
}
132+
133+
#[test]
134+
fn test_bls_verify_precomputed_hash() {
135+
// Sample values taken from other tests
136+
let data = hex::decode("2f901d5cec8722e44afd59e94d0a56bf1506a72a0a60709920aad714d1a2ece0")
137+
.unwrap();
138+
let pk: BLSPubkeyRaw = hex::decode(
139+
"90346f9c5f3c09d96ea02acd0220daa8459f03866ed938c798e3716e42c7e033c9a7ef66a10f83af06d5c00b508c6d0f",
140+
)
141+
.unwrap()
142+
.try_into()
143+
.unwrap();
144+
let sig: BLSSignatureRaw = hex::decode("a9c08eff13742f78f1e5929888f223b5b5b12b4836b5417c5a135cf24f4e2a4c66a6cdef91be3098b7e7a6a63903b61302e3cf2b8653101da245cf01a8d82b25debe7b18a3a2eb1778f8628fd2c59c8687f6e048a31250fbc2804c20043b8443")
145+
.unwrap()
146+
.try_into()
147+
.unwrap();
148+
149+
let pk = G1Affine::from_compressed(&pk).into_option().unwrap();
150+
let sig = G2Affine::from_compressed(&sig).into_option().unwrap();
151+
let hashed = G2Affine::from(hash_message_to_g2(&data));
152+
153+
assert!(bls_verify_precomputed_hash(&pk, &sig, &hashed));
154+
155+
// wrong signature should fail
156+
let mut wrong_sig = sig;
157+
wrong_sig = G2Affine::from(hash_message_to_g2(b"bad"));
158+
assert!(!bls_verify_precomputed_hash(&pk, &wrong_sig, &hashed));
159+
}
160+
161+
#[test]
162+
fn test_to_g1_affine_slow_errors() {
163+
let invalid: BLSPubkeyRaw = [0u8; BLS_PUBKEY_SIZE].into();
164+
assert!(to_g1_affine_slow(&invalid).is_err());
165+
166+
let valid_bytes: BLSPubkeyRaw = hex::decode(
167+
"90346f9c5f3c09d96ea02acd0220daa8459f03866ed938c798e3716e42c7e033c9a7ef66a10f83af06d5c00b508c6d0f",
168+
)
169+
.unwrap()
170+
.try_into()
171+
.unwrap();
172+
let slow = to_g1_affine_slow(&valid_bytes).unwrap();
173+
let fast = to_g1_affine(&valid_bytes);
174+
assert_eq!(slow, fast);
175+
}
176+
177+
#[test]
178+
fn test_to_g2_affine_slow_errors() {
179+
let invalid: BLSSignatureRaw = [0u8; BLS_SIGNATURE_SIZE].into();
180+
assert!(to_g2_affine_slow(&invalid).is_err());
181+
}
182+
}

crates/dkg/src/crypto/bls_keys.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,24 @@ mod tests {
222222

223223
use super::*;
224224

225+
#[test]
226+
fn test_bls_public_key_from_bytes_error() {
227+
let invalid: BLSPubkeyRaw = [0u8; BLS_PUBKEY_SIZE].into();
228+
assert!(BlsPublicKey::from_bytes(&invalid).is_err());
229+
}
230+
231+
#[test]
232+
fn test_bls_secret_key_from_bytes_error() {
233+
let invalid: BLSSecretRaw = [0xffu8; BLS_SECRET_SIZE].into();
234+
assert!(BlsSecretKey::from_bytes(&invalid).is_err());
235+
}
236+
237+
#[test]
238+
fn test_bls_signature_from_bytes_error() {
239+
let invalid: BLSSignatureRaw = [0u8; BLS_SIGNATURE_SIZE].into();
240+
assert!(BlsSignature::from_bytes(&invalid).is_err());
241+
}
242+
225243
#[test]
226244
fn test_bls_id_from_u32() {
227245
let mut bytes: [u8; 32] = [

crates/dkg/src/crypto/secp256k1_keys.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,64 @@ impl CryptoKeys for Secp256k1Crypto {
182182
msg.to_vec()
183183
}
184184
}
185+
186+
#[cfg(test)]
187+
mod tests {
188+
use super::*;
189+
use crate::crypto::traits::ByteConvertible;
190+
use crate::*;
191+
#[test]
192+
fn test_secp256k1_public_key_from_bytes_error() {
193+
let invalid: SECP256K1PubkeyRaw = [0u8; SECP256K1_PUBKEY_SIZE].into();
194+
assert!(Secp256k1PublicKey::from_bytes(&invalid).is_err());
195+
}
196+
197+
#[test]
198+
fn test_secp256k1_secret_key_from_bytes_error() {
199+
let invalid: SECP256K1SecretRaw = [0u8; SECP256K1_SECRET_SIZE].into();
200+
assert!(Secp256k1SecretKey::from_bytes(&invalid).is_err());
201+
}
202+
203+
#[test]
204+
fn test_verify_signature_invalid_message_len() {
205+
let sk_bytes: [u8; 32] = [1u8; 32];
206+
let sk = Secp256k1SecretKey::from_bytes(&crate::types::SECP256K1SecretRaw::from(sk_bytes))
207+
.unwrap();
208+
let pk = sk.to_public_key();
209+
210+
let secp = secp256k1::Secp256k1::new();
211+
let msg = [2u8; 32];
212+
let m = secp256k1::Message::from_digest_slice(&msg).unwrap();
213+
let sig = secp.sign_ecdsa(&m, &sk.secret);
214+
let sig = Secp256k1Signature { sig };
215+
216+
// message that's not 32 bytes should fail
217+
let bad_msg = [1u8; 31];
218+
assert!(!pk.verify_signature(&bad_msg, &sig));
219+
}
220+
221+
#[test]
222+
fn test_secp256k1_roundtrip_and_sign() {
223+
let sk_bytes: [u8; 32] = [1u8; 32];
224+
let raw_sk = crate::types::SECP256K1SecretRaw::from(sk_bytes);
225+
let sk = Secp256k1SecretKey::from_bytes(&raw_sk).unwrap();
226+
let pk = sk.to_public_key();
227+
228+
let raw_pk = pk.to_bytes();
229+
let decoded_pk = Secp256k1PublicKey::from_bytes(&raw_pk).unwrap();
230+
assert_eq!(decoded_pk.to_bytes(), raw_pk);
231+
232+
// sign a hashed message
233+
let msg = [2u8; 32];
234+
let secp = secp256k1::Secp256k1::new();
235+
let m = secp256k1::Message::from_digest_slice(&msg).unwrap();
236+
let sig = secp.sign_ecdsa(&m, &sk.secret);
237+
let sig = Secp256k1Signature { sig };
238+
239+
assert!(pk.verify_signature(&msg, &sig));
240+
241+
// wrong message fails
242+
let bad_msg = [3u8; 32];
243+
assert!(!pk.verify_signature(&bad_msg, &sig));
244+
}
245+
}

crates/dkg/src/verification.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,3 +549,119 @@ where
549549
let expected_key = evaluate_polynomial::<Setup::Curve>(&computed_keys, perpetrator_id);
550550
Setup::Point::from_bytes(&expected_key.to_bytes()).expect("Invalid pubkey")
551551
}
552+
553+
#[cfg(test)]
554+
mod tests {
555+
use super::*;
556+
use crate::crypto::*;
557+
558+
#[test]
559+
fn test_get_index_in_commitments() {
560+
let mut hashes = vec![
561+
SHA256Raw::from([1u8; 32]),
562+
SHA256Raw::from([2u8; 32]),
563+
SHA256Raw::from([0u8; 32]),
564+
];
565+
let dst = SHA256Raw::from([2u8; 32]);
566+
let index = get_index_in_commitments(&hashes, &dst).unwrap();
567+
assert_eq!(index, 2);
568+
hashes.sort();
569+
assert_eq!(hashes[index as usize], dst);
570+
}
571+
572+
#[test]
573+
fn test_initial_commitment_hash_roundtrip() {
574+
type Setup = BlsDkgWithSecp256kCommitment;
575+
576+
let settings = GenerateSettings {
577+
n: 2,
578+
k: 1,
579+
gen_id: DkgGenId::from([1u8; 16]),
580+
};
581+
582+
let pk = <Setup as DkgSetupTypes<Setup>>::Point::identity().to_bytes();
583+
let base_pubkeys = vec![pk.clone(), pk];
584+
585+
let hash = compute_initial_commitment_hash::<Setup>(&settings, &base_pubkeys);
586+
let commitment = InitialCommitment::<Setup> {
587+
hash,
588+
settings: settings.clone(),
589+
base_pubkeys: base_pubkeys.clone(),
590+
};
591+
592+
assert!(verify_initial_commitment_hash::<Setup>(&commitment));
593+
594+
let mut bad = commitment.clone();
595+
bad.base_pubkeys[0].as_mut()[0] ^= 1;
596+
assert!(!verify_initial_commitment_hash::<Setup>(&bad));
597+
}
598+
599+
#[test]
600+
fn test_get_index_in_commitments_not_found() {
601+
let hashes = vec![
602+
SHA256Raw::from([1u8; 32]),
603+
SHA256Raw::from([2u8; 32]),
604+
SHA256Raw::from([3u8; 32]),
605+
];
606+
let dst = SHA256Raw::from([9u8; 32]);
607+
assert!(get_index_in_commitments(&hashes, &dst).is_err());
608+
}
609+
610+
fn dummy_generation(msg: &str) -> Generation<BlsDkgWithSecp256kCommitment> {
611+
Generation {
612+
verification_vector: vec![<BlsDkgWithSecp256kCommitment as DkgSetupTypes<
613+
BlsDkgWithSecp256kCommitment,
614+
>>::Point::identity()
615+
.to_bytes()],
616+
base_hash: SHA256Raw::from([0u8; 32]),
617+
partial_pubkey: <BlsDkgWithSecp256kCommitment as DkgSetupTypes<
618+
BlsDkgWithSecp256kCommitment,
619+
>>::Point::identity()
620+
.to_bytes(),
621+
message_cleartext: msg.to_string(),
622+
message_signature: BLSSignatureRaw([0u8; BLS_SIGNATURE_SIZE]),
623+
}
624+
}
625+
626+
#[test]
627+
fn test_verify_generation_hashes_empty() {
628+
type Setup = BlsDkgWithSecp256kCommitment;
629+
let settings = GenerateSettings {
630+
n: 1,
631+
k: 1,
632+
gen_id: DkgGenId::from([0u8; 16]),
633+
};
634+
assert!(verify_generation_hashes::<Setup>(&[], &settings).is_err());
635+
}
636+
637+
#[test]
638+
fn test_verify_generation_hashes_message_mismatch() {
639+
type Setup = BlsDkgWithSecp256kCommitment;
640+
let settings = GenerateSettings {
641+
n: 2,
642+
k: 1,
643+
gen_id: DkgGenId::from([0u8; 16]),
644+
};
645+
let g1 = dummy_generation("hello");
646+
let mut g2 = dummy_generation("hello");
647+
g2.message_cleartext = "world".to_string();
648+
let gens = vec![g1, g2];
649+
assert!(verify_generation_hashes::<Setup>(&gens, &settings).is_err());
650+
}
651+
652+
#[test]
653+
fn test_verify_generations_wrong_n() {
654+
type Setup = BlsDkgWithSecp256kCommitment;
655+
let settings = GenerateSettings {
656+
n: 2,
657+
k: 1,
658+
gen_id: DkgGenId::from([0u8; 16]),
659+
};
660+
let g = dummy_generation("hello");
661+
let agg_key = <Setup as DkgSetupTypes<Setup>>::DkgPubkey::from_bytes(
662+
&<Setup as DkgSetupTypes<Setup>>::Point::identity().to_bytes(),
663+
)
664+
.unwrap();
665+
assert!(verify_generations::<Setup>(&[g], &settings, &agg_key).is_err());
666+
}
667+
}

0 commit comments

Comments
 (0)