From 5a258711ff43d8f8bf8e9b380df74a338f2c4bcf Mon Sep 17 00:00:00 2001 From: Fiono11 Date: Thu, 9 May 2024 15:07:58 +0100 Subject: [PATCH] WIP --- ed25519-dalek/src/olaf/errors.rs | 24 +++-- ed25519-dalek/src/olaf/mod.rs | 18 +++- ed25519-dalek/src/olaf/simplpedpop.rs | 31 +++--- ed25519-dalek/src/olaf/tests.rs | 39 ++++--- ed25519-dalek/src/olaf/types.rs | 142 ++++++++++++++++++++++---- 5 files changed, 192 insertions(+), 62 deletions(-) diff --git a/ed25519-dalek/src/olaf/errors.rs b/ed25519-dalek/src/olaf/errors.rs index a41ff1de7..a494eba0a 100644 --- a/ed25519-dalek/src/olaf/errors.rs +++ b/ed25519-dalek/src/olaf/errors.rs @@ -9,33 +9,35 @@ pub type DKGResult = Result; /// An error ocurred during the execution of the SimplPedPoP protocol. #[derive(Debug)] pub enum DKGError { - /// Invalid Proof of Possession. - InvalidProofOfPossession(SignatureError), /// Threshold cannot be greater than the number of participants. ExcessiveThreshold, /// Threshold must be at least 2. InsufficientThreshold, /// Number of participants is invalid. InvalidNumberOfParticipants, - /// Invalid PublicKey. + /// Invalid public key. InvalidPublicKey(SignatureError), - /// Invalid Signature. + /// Invalid group public key. + InvalidGroupPublicKey, + /// Invalid signature. InvalidSignature(SignatureError), - /// Invalid Ristretto Point. - InvalidRistrettoPoint, + /// Invalid coefficient commitment of the polynomial commitment. + InvalidCoefficientCommitment, + /// Invalid identifier. + InvalidIdentifier, /// Invalid secret share. InvalidSecretShare, /// Deserialization Error. DeserializationError(TryFromSliceError), - /// The parameters of all messages should be equal. + /// The parameters of all messages must be equal. DifferentParameters, - /// The recipients hash of all messages should be equal. + /// The recipients hash of all messages must be equal. DifferentRecipientsHash, /// The number of messages should be 2 at least, which the minimum number of participants. InvalidNumberOfMessages, - /// The degree of the polynomial commitment be equal to the number of participants - 1. - IncorrectPolynomialCommitmentDegree, - /// The number of encrypted shares per message should be equal to the number of participants. + /// The number of coefficient commitments of the polynomial commitment must be equal to the threshold - 1. + IncorrectNumberOfCoefficientCommitments, + /// The number of encrypted shares per message must be equal to the number of participants. IncorrectNumberOfEncryptedShares, /// Decryption error when decrypting an encrypted secret share. DecryptionError(chacha20poly1305::Error), diff --git a/ed25519-dalek/src/olaf/mod.rs b/ed25519-dalek/src/olaf/mod.rs index 3a1310026..797b1f989 100644 --- a/ed25519-dalek/src/olaf/mod.rs +++ b/ed25519-dalek/src/olaf/mod.rs @@ -32,9 +32,21 @@ impl Identifier { let mut pos = Transcript::new(b"Identifier"); pos.append_message(b"RecipientsHash", recipients_hash); pos.append_message(b"i", &index.to_le_bytes()[..]); - let mut bytes = [0; SCALAR_LENGTH]; - pos.challenge_bytes(b"evaluation position", &mut bytes); - Identifier(Scalar::from_canonical_bytes(bytes).unwrap()) + let mut buf = [0; 64]; + pos.challenge_bytes(b"identifier", &mut buf); + + Identifier(Scalar::from_bytes_mod_order_wide(&buf)) + } +} + +pub(crate) fn scalar_from_canonical_bytes(bytes: [u8; 32]) -> Option { + let key = Scalar::from_canonical_bytes(bytes); + + // Note: this is a `CtOption` so we have to do this to extract the value. + if bool::from(key.is_none()) { + return None; } + + Some(key.unwrap()) } diff --git a/ed25519-dalek/src/olaf/simplpedpop.rs b/ed25519-dalek/src/olaf/simplpedpop.rs index 382b8080c..db82622c5 100644 --- a/ed25519-dalek/src/olaf/simplpedpop.rs +++ b/ed25519-dalek/src/olaf/simplpedpop.rs @@ -77,7 +77,12 @@ impl SigningKey { let recipient = recipients[i as usize]; - let key_exchange: EdwardsPoint = ephemeral_key.to_scalar() * recipient.point; + let key_exchange: EdwardsPoint = secret * recipient.point; + + //println!("secret: {:?}", secret); + println!("point1-A: {:?}", secret * GENERATOR); + //println!("scalar: {:?}", ephemeral_key.to_scalar()); + println!("point2-A: {:?}", recipient.point); let mut encryption_transcript = encryption_transcript.clone(); encryption_transcript.append_message(b"recipient", recipient.as_bytes()); @@ -136,6 +141,12 @@ impl SigningKey { let mut identifiers = Vec::new(); for (j, message) in messages.iter().enumerate() { + message + .content + .sender + .verify(&message.content.to_bytes(), &message.signature) + .map_err(DKGError::InvalidSignature)?; + if &message.content.parameters != parameters { return Err(DKGError::DifferentParameters); } @@ -160,8 +171,8 @@ impl SigningKey { encryption_transcript.append_message(b"contributor", content.sender.as_bytes()); encryption_transcript.append_message(b"nonce", &content.encryption_nonce); - if polynomial_commitment.coefficients_commitments.len() != threshold - 1 { - return Err(DKGError::IncorrectPolynomialCommitmentDegree); + if polynomial_commitment.coefficients_commitments.len() != threshold { + return Err(DKGError::IncorrectNumberOfCoefficientCommitments); } if encrypted_secret_shares.len() != participants { @@ -177,6 +188,11 @@ impl SigningKey { let key_exchange: EdwardsPoint = self.to_scalar() * secret_commitment; + assert!(self.to_scalar() * GENERATOR == self.verifying_key.point); + + println!("point1-B: {:?}", secret_commitment); + println!("point2-B: {:?}", self.to_scalar() * GENERATOR); + encryption_transcript.append_message(b"recipient", self.verifying_key.as_bytes()); encryption_transcript .append_message(b"key exchange", &key_exchange.compress().as_bytes()[..]); @@ -215,15 +231,6 @@ impl SigningKey { group_point += secret_commitment; } - for i in 0..signatures.len() { - self.verifying_key - .verify(&signatures_messages[i], &signatures[i]) - .map_err(DKGError::InvalidSignature)?; - } - - //verify_batch(&mut signatures_transcripts, &signatures, &senders, false) - //.map_err(DKGError::InvalidSignature)?; - for id in &identifiers { let evaluation = total_polynomial_commitment.evaluate(&id.0); verifying_keys.push((*id, VerifyingShare(VerifyingKey::from(evaluation)))); diff --git a/ed25519-dalek/src/olaf/tests.rs b/ed25519-dalek/src/olaf/tests.rs index 6515d83e7..097e2f077 100644 --- a/ed25519-dalek/src/olaf/tests.rs +++ b/ed25519-dalek/src/olaf/tests.rs @@ -10,11 +10,12 @@ mod tests { use crate::{SigningKey, VerifyingKey}; use alloc::vec::Vec; use curve25519_dalek::Scalar; + use ed25519::signature::Signer; use merlin::Transcript; use rand::Rng; use rand_core::OsRng; - const MAXIMUM_PARTICIPANTS: u16 = 10; + const MAXIMUM_PARTICIPANTS: u16 = 2; const MINIMUM_PARTICIPANTS: u16 = 2; const PROTOCOL_RUNS: usize = 1; @@ -41,6 +42,7 @@ mod tests { let mut keypairs: Vec = (0..participants) .map(|_| SigningKey::generate(&mut OsRng)) .collect(); + let public_keys: Vec = keypairs.iter().map(|kp| kp.verifying_key).collect(); @@ -54,7 +56,7 @@ mod tests { let mut dkg_outputs = Vec::new(); - for kp in keypairs.iter() { + for kp in keypairs.iter_mut() { let dkg_output = kp.simplpedpop_recipient_all(&all_messages).unwrap(); dkg_outputs.push(dkg_output); } @@ -81,8 +83,9 @@ mod tests { for i in 0..participants { for j in 0..participants { assert_eq!( - dkg_outputs[i].0.dkg_output.verifying_keys[j].1 .0, - (dkg_outputs[j].1 .0.to_public()), + dkg_outputs[i].0.dkg_output.verifying_keys[j].1 .0.point, + (Scalar::from_canonical_bytes(dkg_outputs[j].1 .0).unwrap() + * GENERATOR), "Verification of total secret shares failed!" ); } @@ -99,11 +102,14 @@ mod tests { let mut keypairs: Vec = (0..participants) .map(|_| SigningKey::generate(&mut rng)) .collect(); - let public_keys: Vec = - keypairs.iter().map(|kp| kp.verifying_key.clone()).collect(); + + let public_keys: Vec = keypairs + .iter_mut() + .map(|kp| kp.verifying_key.clone()) + .collect(); let mut messages: Vec = keypairs - .iter() + .iter_mut() .map(|kp| { kp.simplpedpop_contribute_all(threshold, public_keys.clone()) .unwrap() @@ -175,7 +181,7 @@ mod tests { keypairs.iter().map(|kp| kp.verifying_key.clone()).collect(); let mut messages: Vec = keypairs - .iter() + .iter_mut() .map(|kp| { kp.simplpedpop_contribute_all(threshold, public_keys.clone()) .unwrap() @@ -213,7 +219,7 @@ mod tests { keypairs.iter().map(|kp| kp.verifying_key.clone()).collect(); let mut messages: Vec = keypairs - .iter() + .iter_mut() .map(|kp| { kp.simplpedpop_contribute_all(threshold, public_keys.clone()) .unwrap() @@ -231,9 +237,9 @@ mod tests { match result { Ok(_) => panic!("Expected an error, but got Ok."), Err(e) => match e { - DKGError::IncorrectPolynomialCommitmentDegree => assert!(true), + DKGError::IncorrectNumberOfCoefficientCommitments => assert!(true), _ => panic!( - "Expected DKGError::IncorrectNumberOfCommitments, but got {:?}", + "Expected DKGError::IncorrectNumberOfCoefficientCommitments, but got {:?}", e ), }, @@ -253,7 +259,7 @@ mod tests { keypairs.iter().map(|kp| kp.verifying_key.clone()).collect(); let mut messages: Vec = keypairs - .iter() + .iter_mut() .map(|kp| { kp.simplpedpop_contribute_all(threshold, public_keys.clone()) .unwrap() @@ -289,7 +295,7 @@ mod tests { keypairs.iter().map(|kp| kp.verifying_key.clone()).collect(); let mut messages: Vec = keypairs - .iter() + .iter_mut() .map(|kp| { kp.simplpedpop_contribute_all(threshold, public_keys.clone()) .unwrap() @@ -319,20 +325,19 @@ mod tests { let mut keypairs: Vec = (0..participants) .map(|_| SigningKey::generate(&mut rng)) .collect(); + let public_keys: Vec = keypairs.iter().map(|kp| kp.verifying_key.clone()).collect(); let mut messages: Vec = keypairs - .iter() + .iter_mut() .map(|kp| { kp.simplpedpop_contribute_all(threshold, public_keys.clone()) .unwrap() }) .collect(); - messages[1].signature = keypairs[1] - .secret - .sign(Transcript::new(b"invalid"), &keypairs[1].public); + messages[1].signature = keypairs[1].sign(b"invalid"); let result = keypairs[0].simplpedpop_recipient_all(&messages); diff --git a/ed25519-dalek/src/olaf/types.rs b/ed25519-dalek/src/olaf/types.rs index f64b68441..93005f48f 100644 --- a/ed25519-dalek/src/olaf/types.rs +++ b/ed25519-dalek/src/olaf/types.rs @@ -2,7 +2,8 @@ use super::{ errors::{DKGError, DKGResult}, - GroupPublicKey, Identifier, VerifyingShare, GENERATOR, MINIMUM_THRESHOLD, + scalar_from_canonical_bytes, GroupPublicKey, Identifier, VerifyingShare, GENERATOR, + MINIMUM_THRESHOLD, }; use crate::{VerifyingKey, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH}; use alloc::vec::Vec; @@ -14,8 +15,8 @@ use merlin::Transcript; use rand_core::{CryptoRng, RngCore}; use zeroize::ZeroizeOnDrop; -pub(super) const COMPRESSED_RISTRETTO_LENGTH: usize = 32; -pub(super) const U16_LENGTH: usize = 2; +pub(super) const COMPRESSED_EDWARDS_LENGTH: usize = 32; +pub(super) const VEC_LENGTH: usize = 2; pub(super) const ENCRYPTION_NONCE_LENGTH: usize = 12; pub(super) const RECIPIENTS_HASH_LENGTH: usize = 16; pub(super) const CHACHA20POLY1305_LENGTH: usize = 64; @@ -113,7 +114,7 @@ pub(super) struct SecretPolynomial { impl SecretPolynomial { pub(super) fn generate(degree: usize, rng: &mut R) -> Self { - let mut coefficients = Vec::with_capacity(degree); + let mut coefficients = Vec::with_capacity(degree + 1); let mut first = Scalar::random(rng); while first == Scalar::ZERO { @@ -121,7 +122,7 @@ impl SecretPolynomial { } coefficients.push(first); - coefficients.extend(iter::repeat_with(|| Scalar::random(rng)).take(degree - 1)); + coefficients.extend(iter::repeat_with(|| Scalar::random(rng)).take(degree)); SecretPolynomial { coefficients } } @@ -306,17 +307,17 @@ impl MessageContent { cursor += ENCRYPTION_NONCE_LENGTH; let participants = u16::from_le_bytes( - bytes[cursor..cursor + U16_LENGTH] + bytes[cursor..cursor + VEC_LENGTH] .try_into() .map_err(DKGError::DeserializationError)?, ); - cursor += U16_LENGTH; + cursor += VEC_LENGTH; let threshold = u16::from_le_bytes( - bytes[cursor..cursor + U16_LENGTH] + bytes[cursor..cursor + VEC_LENGTH] .try_into() .map_err(DKGError::DeserializationError)?, ); - cursor += U16_LENGTH; + cursor += VEC_LENGTH; let recipients_hash: [u8; RECIPIENTS_HASH_LENGTH] = bytes [cursor..cursor + RECIPIENTS_HASH_LENGTH] @@ -327,15 +328,17 @@ impl MessageContent { let mut coefficients_commitments = Vec::with_capacity(participants as usize); for _ in 0..participants { - let point = CompressedEdwardsY::from_slice( - &bytes[cursor..cursor + COMPRESSED_RISTRETTO_LENGTH], - ) - .map_err(DKGError::DeserializationError)?; + let point = + CompressedEdwardsY::from_slice(&bytes[cursor..cursor + COMPRESSED_EDWARDS_LENGTH]) + .map_err(DKGError::DeserializationError)?; - coefficients_commitments - .push(point.decompress().ok_or(DKGError::InvalidRistrettoPoint)?); + coefficients_commitments.push( + point + .decompress() + .ok_or(DKGError::InvalidCoefficientCommitment)?, + ); - cursor += COMPRESSED_RISTRETTO_LENGTH; + cursor += COMPRESSED_EDWARDS_LENGTH; } let polynomial_commitment = PolynomialCommitment { @@ -468,16 +471,20 @@ impl DKGOutput { public_key_bytes.copy_from_slice(&bytes[cursor..cursor + PUBLIC_KEY_LENGTH]); cursor += PUBLIC_KEY_LENGTH; - let group_public_key = GroupPublicKey(VerifyingKey::from_bytes(&public_key_bytes).unwrap()); + let group_public_key = GroupPublicKey( + VerifyingKey::from_bytes(&public_key_bytes).map_err(DKGError::InvalidPublicKey)?, + ); - cursor += U16_LENGTH; + cursor += VEC_LENGTH; let mut verifying_keys = Vec::new(); while cursor < bytes.len() { let mut identifier_bytes = [0; SCALAR_LENGTH]; identifier_bytes.copy_from_slice(&bytes[cursor..cursor + SCALAR_LENGTH]); - let identifier = Scalar::from_canonical_bytes(identifier_bytes).unwrap(); + + let identifier = + scalar_from_canonical_bytes(identifier_bytes).ok_or(DKGError::InvalidIdentifier)?; cursor += SCALAR_LENGTH; let mut vk_bytes = [0; PUBLIC_KEY_LENGTH]; @@ -678,4 +685,101 @@ mod tests { .decrypt(&key_bytes, &encryption_nonce) .unwrap(); } + + #[test] + fn test_generate_polynomial_commitment_valid() { + let degree = 3; + + let polynomial = SecretPolynomial::generate(degree, &mut OsRng); + + let polynomial_commitment = PolynomialCommitment::commit(&polynomial); + + assert_eq!(polynomial.coefficients.len(), degree as usize + 1); + + assert_eq!( + polynomial_commitment.coefficients_commitments.len(), + degree as usize + 1 + ); + } + + #[test] + fn test_evaluate_polynomial() { + let coefficients: Vec = + vec![Scalar::from(3u64), Scalar::from(2u64), Scalar::from(1u64)]; // Polynomial x^2 + 2x + 3 + + let polynomial = SecretPolynomial { coefficients }; + + let value = Scalar::from(5u64); // x = 5 + + let result = polynomial.evaluate(&value); + + assert_eq!(result, Scalar::from(38u64)); // 5^2 + 2*5 + 3 + } + + #[test] + fn test_sum_secret_polynomial_commitments() { + let polynomial_commitment1 = PolynomialCommitment { + coefficients_commitments: vec![ + GENERATOR * Scalar::from(1u64), // Constant + GENERATOR * Scalar::from(2u64), // Linear + GENERATOR * Scalar::from(3u64), // Quadratic + ], + }; + + let polynomial_commitment2 = PolynomialCommitment { + coefficients_commitments: vec![ + GENERATOR * Scalar::from(4u64), // Constant + GENERATOR * Scalar::from(5u64), // Linear + GENERATOR * Scalar::from(6u64), // Quadratic + ], + }; + + let summed_polynomial_commitments = PolynomialCommitment::sum_polynomial_commitments(&[ + &polynomial_commitment1, + &polynomial_commitment2, + ]); + + let expected_coefficients_commitments = vec![ + GENERATOR * Scalar::from(5u64), // 1 + 4 = 5 + GENERATOR * Scalar::from(7u64), // 2 + 5 = 7 + GENERATOR * Scalar::from(9u64), // 3 + 6 = 9 + ]; + + assert_eq!( + summed_polynomial_commitments.coefficients_commitments, + expected_coefficients_commitments, + "Coefficient commitments do not match" + ); + } + + #[test] + fn test_evaluate_polynomial_commitment() { + // f(x) = 3 + 2x + x^2 + let constant_coefficient_commitment = Scalar::from(3u64) * GENERATOR; + let linear_commitment = Scalar::from(2u64) * GENERATOR; + let quadratic_commitment = Scalar::from(1u64) * GENERATOR; + + // Note the order and inclusion of the constant term + let coefficients_commitments = vec![ + constant_coefficient_commitment, + linear_commitment, + quadratic_commitment, + ]; + + let polynomial_commitment = PolynomialCommitment { + coefficients_commitments, + }; + + let value = Scalar::from(2u64); + + // f(2) = 11 + let expected = Scalar::from(11u64) * GENERATOR; + + let result = polynomial_commitment.evaluate(&value); + + assert_eq!( + result, expected, + "The evaluated commitment does not match the expected result" + ); + } }