diff --git a/synedrion/src/cggmp21.rs b/synedrion/src/cggmp21.rs index 06571347..e5b56dbb 100644 --- a/synedrion/src/cggmp21.rs +++ b/synedrion/src/cggmp21.rs @@ -19,6 +19,9 @@ mod sigma; #[cfg(test)] mod signing_malicious; +#[cfg(test)] +mod key_init_malicious; + pub use aux_gen::{AuxGen, AuxGenProtocol}; pub use entities::{AuxInfo, KeyShare, KeyShareChange}; pub use interactive_signing::{InteractiveSigning, InteractiveSigningProtocol, PrehashedMessage}; diff --git a/synedrion/src/cggmp21/entities.rs b/synedrion/src/cggmp21/entities.rs index b2aa0a54..6119b026 100644 --- a/synedrion/src/cggmp21/entities.rs +++ b/synedrion/src/cggmp21/entities.rs @@ -24,12 +24,12 @@ use crate::{ /// The result of the KeyInit protocol. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct KeyShare
{
- pub(crate) owner: I,
+ owner: I,
/// Secret key share of this node.
- pub(crate) secret_share: Secret ,
+ phantom: PhantomData ,
}
/// The result of the AuxGen protocol.
@@ -125,7 +125,23 @@ pub(crate) struct PresigningValues {
+impl {
+ pub(crate) fn new(
+ owner: I,
+ secret_share: Secret ) -> Result {
&self.owner
}
+ pub(crate) fn secret_share(&self) -> &Secret {
}
let other_ids = key_share
- .public_shares
+ .public_shares()
.keys()
.cloned()
.collect:: {
let ssid_hash = FofHasher::new_with_dst(b"ShareSetID")
.chain_type:: ()
.chain(&shared_randomness)
- .chain(&key_share.public_shares)
+ .chain(&key_share.public_shares())
.chain(&aux_info.public_aux)
.finalize();
@@ -221,11 +221,11 @@ struct Context Context
where
P: SchemeParams,
- I: Ord + Debug,
+ I: Clone + Ord + Debug,
{
pub fn public_share(&self, i: &I) -> Result<&Point, LocalError> {
self.key_share
- .public_shares
+ .public_shares()
.get(i)
.ok_or_else(|| LocalError::new("Missing public_share for party Id {i:?}"))
}
@@ -507,7 +507,7 @@ impl {
let hat_s = Randomizer::random(rng, target_pk);
let gamma = secret_signed_from_scalar:: (&self.context.gamma);
- let x = secret_signed_from_scalar:: (&self.context.key_share.secret_share);
+ let x = secret_signed_from_scalar:: (self.context.key_share.secret_share());
let others_cap_k = self
.all_cap_k
@@ -518,7 +518,7 @@ impl {
let cap_d = others_cap_k * &gamma + Ciphertext::new_with_randomizer(target_pk, &-&beta, &s);
let hat_cap_f = Ciphertext::new_with_randomizer(pk, &hat_beta, &hat_r);
- let hat_cap_d = others_cap_k * &secret_signed_from_scalar:: (&self.context.key_share.secret_share)
+ let hat_cap_d = others_cap_k * &secret_signed_from_scalar:: (self.context.key_share.secret_share())
+ Ciphertext::new_with_randomizer(target_pk, &-&hat_beta, &hat_s);
let cap_g = self.all_cap_g.get(&self.context.my_id).ok_or(LocalError::new(format!(
@@ -737,7 +737,7 @@ impl {
let hat_alpha_sum: SecretSigned<_> = payloads.values().map(|payload| &payload.hat_alpha).sum();
let hat_beta_sum: SecretSigned<_> = artifacts.values().map(|artifact| &artifact.hat_beta).sum();
- let chi = secret_signed_from_scalar:: (&self.context.key_share.secret_share)
+ let chi = secret_signed_from_scalar:: (self.context.key_share.secret_share())
* secret_signed_from_scalar:: (&self.context.k)
+ &hat_alpha_sum
+ &hat_beta_sum;
@@ -1257,7 +1257,7 @@ impl {
let p_aff_g = AffGProof:: ::new(
rng,
AffGSecretInputs {
- x: &secret_signed_from_scalar:: (&self.context.key_share.secret_share),
+ x: &secret_signed_from_scalar:: (self.context.key_share.secret_share()),
y: &values.hat_beta,
rho: &values.hat_s,
rho_y: &values.hat_r,
@@ -1293,7 +1293,7 @@ impl {
// mul* proofs
- let x = &self.context.key_share.secret_share;
+ let x = &self.context.key_share.secret_share();
let cap_x = self.context.public_share(&my_id)?;
let rho = Randomizer::random(rng, pk);
diff --git a/synedrion/src/cggmp21/key_init.rs b/synedrion/src/cggmp21/key_init.rs
index 892a134b..b767544a 100644
--- a/synedrion/src/cggmp21/key_init.rs
+++ b/synedrion/src/cggmp21/key_init.rs
@@ -1,17 +1,21 @@
-//! KeyInit protocol, in the paper ECDSA Key-Generation (Fig. 5).
+//! KeyInit protocol, in the paper ECDSA Key-Generation (Fig. 6).
//! Note that this protocol only generates the key itself which is not enough to perform signing;
//! auxiliary parameters need to be generated as well (during the KeyRefresh protocol).
use alloc::{
collections::{BTreeMap, BTreeSet},
- format,
+ vec::Vec,
+};
+use core::{
+ fmt::{self, Debug, Display},
+ marker::PhantomData,
};
-use core::{fmt::Debug, marker::PhantomData};
use manul::protocol::{
Artifact, BoxedRound, Deserializer, DirectMessage, EchoBroadcast, EntryPoint, FinalizeOutcome, LocalError,
MessageValidationError, NormalBroadcast, PartyId, Payload, Protocol, ProtocolError, ProtocolMessage,
- ProtocolMessagePart, ProtocolValidationError, ReceiveError, RequiredMessages, Round, RoundId, Serializer,
+ ProtocolMessagePart, ProtocolValidationError, ReceiveError, RequiredMessageParts, RequiredMessages, Round, RoundId,
+ Serializer,
};
use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize};
@@ -26,7 +30,7 @@ use crate::{
tools::{
bitvec::BitVec,
hashing::{Chain, FofHasher, HashOutput},
- DowncastMap, Secret, Without,
+ DowncastMap, SafeGet, Secret, Without,
},
};
@@ -36,70 +40,176 @@ pub struct KeyInitProtocol {
type Result = KeyShare ;
- type ProtocolError = KeyInitError;
+ type ProtocolError = KeyInitError ;
fn verify_direct_message_is_invalid(
_deserializer: &Deserializer,
- _round_id: &RoundId,
- _message: &DirectMessage,
+ round_id: &RoundId,
+ message: &DirectMessage,
) -> Result<(), MessageValidationError> {
- unimplemented!()
+ if round_id == &RoundId::new(1) || round_id == &RoundId::new(2) || round_id == &RoundId::new(3) {
+ message.verify_is_some()
+ } else {
+ Err(MessageValidationError::InvalidEvidence("Invalid round number".into()))
+ }
}
fn verify_echo_broadcast_is_invalid(
- _deserializer: &Deserializer,
- _round_id: &RoundId,
- _message: &EchoBroadcast,
+ deserializer: &Deserializer,
+ round_id: &RoundId,
+ message: &EchoBroadcast,
) -> Result<(), MessageValidationError> {
- unimplemented!()
+ match round_id {
+ r if r == &RoundId::new(1) => message.verify_is_not:: {
+ error: KeyInitErrorEnum,
+ phantom: PhantomData ,
+}
+
+impl Display for KeyInitError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(f, "{}", self.error)
+ }
+}
+
+impl KeyInitError {
+ fn new(error: KeyInitErrorEnum) -> Self {
+ Self {
+ error,
+ phantom: PhantomData,
+ }
+ }
+}
+
#[derive(displaydoc::Display, Debug, Clone, Copy, Serialize, Deserialize)]
-pub enum KeyInitError {
+enum KeyInitErrorEnum {
/// A hash mismatch in Round 2.
R2HashMismatch,
/// Failed to verify `П^sch` in Round 3.
R3InvalidSchProof,
}
-impl ProtocolError for KeyInitError {
+impl {
type AssociatedData = ();
fn required_messages(&self) -> RequiredMessages {
- unimplemented!()
+ match self.error {
+ KeyInitErrorEnum::R2HashMismatch => RequiredMessages::new(
+ RequiredMessageParts::echo_broadcast_only(),
+ Some([(RoundId::new(1), RequiredMessageParts::echo_broadcast_only())].into()),
+ None,
+ ),
+ KeyInitErrorEnum::R3InvalidSchProof => RequiredMessages::new(
+ RequiredMessageParts::normal_broadcast_only(),
+ Some([(RoundId::new(2), RequiredMessageParts::echo_broadcast_only())].into()),
+ Some([RoundId::new(2)].into()),
+ ),
+ }
}
fn verify_messages_constitute_error(
&self,
- _deserializer: &Deserializer,
- _guilty_party: &I,
- _shared_randomness: &[u8],
+ deserializer: &Deserializer,
+ guilty_party: &I,
+ shared_randomness: &[u8],
_associated_data: &Self::AssociatedData,
- _message: ProtocolMessage,
- _previous_messages: BTreeMap ()
+ .chain(&shared_randomness)
+ .finalize();
+
+ match self.error {
+ KeyInitErrorEnum::R2HashMismatch => {
+ let r1_serialized = &previous_messages
+ .get(&RoundId::new(1))
+ .ok_or_else(|| {
+ ProtocolValidationError::InvalidEvidence("Missing echo broadcast from Round 1".into())
+ })?
+ .echo_broadcast;
+ let r1_message = r1_serialized.deserialize:: ,
+pub(super) struct PublicData ,
}
impl {
@@ -148,7 +258,6 @@ impl {
let sid_hash = FofHasher::new_with_dst(b"SID")
.chain_type:: ()
.chain(&shared_randomness)
- .chain(&self.all_ids)
.finalize();
// The secret share
@@ -156,7 +265,7 @@ impl {
// The public share
let cap_x = x.mul_by_generator();
- let rid = BitVec::random(rng, P::SECURITY_PARAMETER);
+ let rho = BitVec::random(rng, P::SECURITY_PARAMETER);
let tau = SchSecret::random(rng);
let cap_a = SchCommitment::new(&tau);
let u = BitVec::random(rng, P::SECURITY_PARAMETER);
@@ -164,7 +273,7 @@ impl {
let public_data = PublicData {
cap_x,
cap_a,
- rid,
+ rho,
u,
phantom: PhantomData,
};
@@ -183,13 +292,13 @@ impl {
}
#[derive(Debug)]
-struct Context ,
- sid_hash: HashOutput,
+pub(super) struct Context ,
+ pub(super) sid_hash: HashOutput,
}
#[derive(Debug)]
@@ -198,7 +307,7 @@ struct Round1 {
.context
.public_data
.hash(&self.context.sid_hash, &self.context.my_id);
- EchoBroadcast::new(serializer, Round1Message { cap_v })
+ EchoBroadcast::new(serializer, Round1EchoBroadcast { cap_v })
}
fn receive_message(
@@ -246,7 +355,9 @@ impl {
) -> Result : Serialize"))]
#[serde(bound(deserialize = "PublicData : for<'x> Deserialize<'x>"))]
-struct Round2Message ,
+pub(super) struct Round2EchoBroadcast ,
}
struct Round2Payload {
) -> Result {
) -> Result {
payloads: BTreeMap,
_artifacts: BTreeMap,
) -> Result {
Ok(FinalizeOutcome::AnotherRound(BoxedRound::new_dynamic(Round3 {
context: self.context,
others_data,
- rid,
+ rho,
phantom: PhantomData,
})))
}
}
#[derive(Debug)]
-struct Round3 ,
- others_data: BTreeMap>,
- rid: BitVec,
- phantom: PhantomData ,
+pub(super) struct Round3 ,
+ pub(super) others_data: BTreeMap>,
+ pub(super) rho: BitVec,
+ pub(super) phantom: PhantomData ,
}
#[derive(Clone, Serialize, Deserialize)]
-struct Round3Message {
- psi: SchProof,
+pub(super) struct Round3Broadcast {
+ pub(super) psi: SchProof,
}
impl {
@@ -404,7 +516,7 @@ impl {
_rng: &mut impl CryptoRngCore,
serializer: &Serializer,
) -> Result {
&self.context.public_data.cap_x,
&aux,
);
- NormalBroadcast::new(serializer, Round3Message { psi })
+ NormalBroadcast::new(serializer, Round3Broadcast { psi })
}
fn receive_message(
@@ -424,17 +536,15 @@ impl {
) -> Result {
.map(|(k, v)| (k, v.cap_x))
.collect:: ::new(my_id, self.context.x, public_shares)?;
+
+ Ok(FinalizeOutcome::Result(key_share))
}
}
@@ -500,7 +611,7 @@ mod tests {
let public_sets = shares
.iter()
- .map(|(id, share)| (*id, share.public_shares.clone()))
+ .map(|(id, share)| (*id, share.public_shares().clone()))
.collect:: (PhantomData );
+
+impl {
+ type EntryPoint = KeyInit ;
+
+ fn modify_echo_broadcast(
+ rng: &mut impl CryptoRngCore,
+ round: &BoxedRound = MisbehavingEntryPoint >()?;
- Ok(KeyShare {
- owner: self.owner.clone(),
- secret_share,
- public_shares,
- phantom: PhantomData,
- })
+ KeyShare::new(self.owner.clone(), secret_share, public_shares)
}
/// Creates a t-of-t threshold keyshare that can be used in KeyResharing protocol.
@@ -196,7 +191,7 @@ impl ThresholdKeyShare ThresholdKeyShare