From 59c943915c4d27ca59c51546130a78a0f8370d1c Mon Sep 17 00:00:00 2001 From: Bogdan Opanchuk Date: Fri, 10 Jan 2025 17:21:24 -0800 Subject: [PATCH] [in progress] Update Presigning and Signing --- synedrion/src/cggmp21.rs | 4 +- synedrion/src/cggmp21/entities.rs | 37 +- synedrion/src/cggmp21/interactive_signing.rs | 1155 ++++++------------ synedrion/src/cggmp21/sigma.rs | 2 + 4 files changed, 405 insertions(+), 793 deletions(-) diff --git a/synedrion/src/cggmp21.rs b/synedrion/src/cggmp21.rs index cc9da2a..99ba335 100644 --- a/synedrion/src/cggmp21.rs +++ b/synedrion/src/cggmp21.rs @@ -16,8 +16,8 @@ mod key_refresh; mod params; mod sigma; -#[cfg(test)] -mod signing_malicious; +//#[cfg(test)] +//mod signing_malicious; #[cfg(test)] mod key_init_tests; diff --git a/synedrion/src/cggmp21/entities.rs b/synedrion/src/cggmp21/entities.rs index 7760a16..3fca66a 100644 --- a/synedrion/src/cggmp21/entities.rs +++ b/synedrion/src/cggmp21/entities.rs @@ -14,11 +14,9 @@ use crate::{ cggmp21::SchemeParams, curve::{secret_split, Point, Scalar}, paillier::{ - Ciphertext, PaillierParams, PublicKeyPaillier, PublicKeyPaillierWire, RPParams, RPParamsWire, Randomizer, - SecretKeyPaillier, SecretKeyPaillierWire, + PublicKeyPaillier, PublicKeyPaillierWire, RPParams, RPParamsWire, SecretKeyPaillier, SecretKeyPaillierWire, }, tools::Secret, - uint::SecretSigned, }; /// The result of the KeyInit protocol. @@ -86,39 +84,6 @@ pub struct KeyShareChange { pub(crate) phantom: PhantomData

, } -/// The result of the Presigning protocol. -#[derive(Debug, Clone)] -pub(crate) struct PresigningData { - pub(crate) nonce: Scalar, // x-coordinate of $R$ - /// An additive share of the ephemeral scalar. - pub(crate) ephemeral_scalar_share: Secret, // $k_i$ - /// An additive share of `k * x` where `x` is the secret key. - pub(crate) product_share: Secret, - - // Values generated during presigning, - // kept in case we need to generate a proof of correctness. - pub(crate) product_share_nonreduced: SecretSigned<::Uint>, - - // $K_i$. - pub(crate) cap_k: Ciphertext, - - // The values for $j$, $j != i$. - pub(crate) values: BTreeMap>, -} - -#[derive(Debug, Clone)] -pub(crate) struct PresigningValues { - pub(crate) hat_beta: SecretSigned<::Uint>, - pub(crate) hat_r: Randomizer, - pub(crate) hat_s: Randomizer, - pub(crate) cap_k: Ciphertext, - /// Received $\hat{D}_{i,j}$. - pub(crate) hat_cap_d_received: Ciphertext, - /// Sent $\hat{D}_{j,i}$. - pub(crate) hat_cap_d: Ciphertext, - pub(crate) hat_cap_f: Ciphertext, -} - impl KeyShare { pub(crate) fn new( owner: I, diff --git a/synedrion/src/cggmp21/interactive_signing.rs b/synedrion/src/cggmp21/interactive_signing.rs index 311a46e..b229cb8 100644 --- a/synedrion/src/cggmp21/interactive_signing.rs +++ b/synedrion/src/cggmp21/interactive_signing.rs @@ -1,11 +1,8 @@ -//! Merged Presigning and Signing protocols, -//! in the paper ECDSA Pre-Signing (Fig. 7) and Signing (Fig. 8). +//! ECDSA Pre-Signing protocol (Fig. 8). use alloc::{ collections::{BTreeMap, BTreeSet}, - format, string::String, - vec::Vec, }; use core::{fmt::Debug, marker::PhantomData}; @@ -19,13 +16,12 @@ use rand_core::CryptoRngCore; use serde::{Deserialize, Serialize}; use super::{ - conversion::{public_signed_from_scalar, secret_scalar_from_signed, secret_signed_from_scalar}, - entities::{AuxInfo, AuxInfoPrecomputed, KeyShare, PresigningData, PresigningValues, PublicAuxInfoPrecomputed}, + conversion::{secret_scalar_from_signed, secret_signed_from_scalar}, + entities::{AuxInfo, AuxInfoPrecomputed, KeyShare, PublicAuxInfoPrecomputed}, params::SchemeParams, sigma::{ - AffGProof, AffGPublicInputs, AffGSecretInputs, DecProof, DecPublicInputs, DecSecretInputs, EncProof, - EncPublicInputs, EncSecretInputs, LogStarProof, LogStarPublicInputs, LogStarSecretInputs, MulProof, - MulPublicInputs, MulSecretInputs, MulStarProof, MulStarPublicInputs, MulStarSecretInputs, + AffGProof, AffGPublicInputs, AffGSecretInputs, ElogProof, ElogPublicInputs, ElogSecretInputs, EncElgProof, + EncElgPublicInputs, EncElgSecretInputs, }, }; use crate::{ @@ -33,12 +29,24 @@ use crate::{ paillier::{Ciphertext, CiphertextWire, PaillierParams, Randomizer}, tools::{ hashing::{Chain, FofHasher, HashOutput}, - protocol_shortcuts::{DowncastMap, Without}, + protocol_shortcuts::{DowncastMap, SafeGet, Without}, Secret, }, uint::SecretSigned, }; +/// Prehashed message to sign. +pub type PrehashedMessage = [u8; 32]; + +#[derive(Debug, Clone)] +pub(crate) struct PresigningData { + pub(crate) cap_gamma: Point, + pub(crate) tilde_k: Scalar, // $k / \delta$ + pub(crate) tilde_chi: Scalar, // $chi / \delta$ + pub(crate) tilde_cap_deltas: BTreeMap, // $\Delta_j^{\delta^{-1}}$ for all $j$ + pub(crate) tilde_cap_ss: BTreeMap, // $S_j^{\delta^{-1}}$ for all $j$ +} + /// A protocol for creating all the data necessary for signing /// that doesn't require knowing the actual message being signed. #[derive(Debug, Clone, Copy)] @@ -73,21 +81,15 @@ impl Protocol for InteractiveSigningProtocol ProtocolError for InteractiveSigningError { @@ -111,25 +113,22 @@ impl ProtocolError for InteractiveSigningError { } } -/// Prehashed message to sign. -pub type PrehashedMessage = [u8; 32]; - /// An entry point for the [`InteractiveSigningProtocol`]. #[derive(Debug)] pub struct InteractiveSigning { key_share: KeyShare, aux_info: AuxInfo, - prehashed_message: PrehashedMessage, + scalar_message: Scalar, } -impl InteractiveSigning { +impl InteractiveSigning { /// Creates a new entry point given a share of the secret key. - pub fn new(prehashed_message: PrehashedMessage, key_share: KeyShare, aux_info: AuxInfo) -> Self { + pub fn new(message: PrehashedMessage, key_share: KeyShare, aux_info: AuxInfo) -> Self { // TODO: check that both are consistent Self { - prehashed_message, key_share, aux_info, + scalar_message: Scalar::from_reduced_bytes(&message), } } } @@ -163,10 +162,10 @@ impl EntryPoint for InteractiveSigning { .collect::>() .without(id); - // This includes the info of $ssid$ in the paper - // (scheme parameters + public data from all shares - hashed in `share_set_id`), - // with the session randomness added. - let ssid_hash = FofHasher::new_with_dst(b"ShareSetID") + // This includes the info of $epid$ in the paper + // (scheme parameters + public data from all shares), with the session randomness added. + // TODO: include `rid`? Need to save it in the KeyInit + let epid_hash = FofHasher::new_with_dst(b"EPID") .chain_type::

() .chain(&shared_randomness) .chain(&key_share.public_shares()) @@ -190,35 +189,62 @@ impl EntryPoint for InteractiveSigning { let rho = Randomizer::::random(rng, pk); let cap_k = Ciphertext::new_with_randomizer(pk, &secret_signed_from_scalar::

(&k), &rho); + let y = Secret::init_with(|| Scalar::random(rng)); + let cap_y = y.mul_by_generator(); + + let a = Secret::init_with(|| Scalar::random(rng)); + let b = Secret::init_with(|| Scalar::random(rng)); + let cap_a1 = a.mul_by_generator(); + let cap_a2 = cap_y * &a + k.mul_by_generator(); + let cap_b1 = b.mul_by_generator(); + let cap_b2 = cap_y * &b + gamma.mul_by_generator(); + + let r1_echo_broadcast = Round1EchoBroadcast { + cap_k: cap_k.to_wire(), + cap_g: cap_g.to_wire(), + cap_y, + cap_a1, + cap_a2, + cap_b1, + cap_b2, + }; + Ok(BoxedRound::new_dynamic(Round1 { context: Context { - ssid_hash, + scalar_message: self.scalar_message, + epid_hash, my_id: id.clone(), - message: Scalar::from_reduced_bytes(&self.prehashed_message), other_ids, key_share, aux_info, k, gamma, + y, + a, + b, rho, nu, }, cap_k, cap_g, + r1_echo_broadcast, })) } } #[derive(Debug)] struct Context { - ssid_hash: HashOutput, + scalar_message: Scalar, + epid_hash: HashOutput, my_id: I, - message: Scalar, other_ids: BTreeSet, key_share: KeyShare, aux_info: AuxInfoPrecomputed, k: Secret, gamma: Secret, + y: Secret, + a: Secret, + b: Secret, rho: Randomizer, nu: Randomizer, } @@ -229,55 +255,52 @@ where I: Clone + Ord + Debug, { pub fn public_share(&self, i: &I) -> Result<&Point, LocalError> { - self.key_share - .public_shares() - .get(i) - .ok_or_else(|| LocalError::new("Missing public_share for party Id {i:?}")) + self.key_share.public_shares().safe_get("public share", i) } pub fn public_aux(&self, i: &I) -> Result<&PublicAuxInfoPrecomputed

, LocalError> { - self.aux_info - .public_aux - .get(i) - .ok_or_else(|| LocalError::new(format!("Missing public_aux for party Id {i:?}"))) + self.aux_info.public_aux.safe_get("public aux", i) } } #[derive(Debug)] struct Round1 { context: Context, + r1_echo_broadcast: Round1EchoBroadcast

, cap_k: Ciphertext, cap_g: Ciphertext, } -impl Round1 { - fn public_aux(&self, i: &I) -> Result<&PublicAuxInfoPrecomputed

, LocalError> { - self.context - .aux_info - .public_aux - .get(i) - .ok_or_else(|| LocalError::new(format!("Missing public_aux for party Id {i:?}"))) - } -} - -#[derive(Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound(serialize = "CiphertextWire: Serialize"))] #[serde(bound(deserialize = "CiphertextWire: for<'x> Deserialize<'x>"))] -struct Round1BroadcastMessage { +struct Round1EchoBroadcast { cap_k: CiphertextWire, cap_g: CiphertextWire, + cap_y: Point, + cap_a1: Point, + cap_a2: Point, + cap_b1: Point, + cap_b2: Point, } #[derive(Clone, Serialize, Deserialize)] -#[serde(bound(serialize = "EncProof

: Serialize"))] -#[serde(bound(deserialize = "EncProof

: for<'x> Deserialize<'x>"))] +#[serde(bound(serialize = "EncElgProof

: Serialize"))] +#[serde(bound(deserialize = "EncElgProof

: for<'x> Deserialize<'x>"))] struct Round1DirectMessage { - psi0: EncProof

, + psi0: EncElgProof

, + psi1: EncElgProof

, } +#[derive(Debug)] struct Round1Payload { - cap_k: CiphertextWire, - cap_g: CiphertextWire, + cap_k: Ciphertext, + cap_g: Ciphertext, + cap_y: Point, + cap_a1: Point, + cap_a2: Point, + cap_b1: Point, + cap_b2: Point, } impl Round for Round1 { @@ -304,13 +327,7 @@ impl Round for Round1 { _rng: &mut impl CryptoRngCore, serializer: &Serializer, ) -> Result { - EchoBroadcast::new( - serializer, - Round1BroadcastMessage::

{ - cap_k: self.cap_k.to_wire(), - cap_g: self.cap_g.to_wire(), - }, - ) + EchoBroadcast::new(serializer, self.r1_echo_broadcast.clone()) } fn make_direct_message( @@ -319,22 +336,65 @@ impl Round for Round1 { serializer: &Serializer, destination: &I, ) -> Result<(DirectMessage, Option), LocalError> { - let aux = (&self.context.ssid_hash, &destination); - let psi0 = EncProof::new( + let aux = (&self.context.epid_hash, &destination); + let pk = self.context.aux_info.secret_aux.paillier_sk.public_key(); + + let psi0 = EncElgProof::new( rng, - EncSecretInputs { - k: &secret_signed_from_scalar::

(&self.context.k), + EncElgSecretInputs { + x: &secret_signed_from_scalar::

(&self.context.k), rho: &self.context.rho, + // Note that the paper does not mention `y` (Elgamal secret) as an input, + // but it is required according to the definition of enc-elg protocol. + a: &self.context.y, + b: &self.context.a, }, - EncPublicInputs { - pk0: self.context.aux_info.secret_aux.paillier_sk.public_key(), - cap_k: &self.cap_k, + EncElgPublicInputs { + pk0: pk, + cap_c: &self.r1_echo_broadcast.cap_k.to_precomputed(pk), + cap_a: &self.r1_echo_broadcast.cap_y, + cap_b: &self.r1_echo_broadcast.cap_a1, + cap_x: &self.r1_echo_broadcast.cap_a2, }, - &self.public_aux(destination)?.rp_params, + &self + .context + .aux_info + .public_aux + .safe_get("public aux", destination)? + .rp_params, &aux, ); - Ok((DirectMessage::new(serializer, Round1DirectMessage::

{ psi0 })?, None)) + let psi1 = EncElgProof::new( + rng, + EncElgSecretInputs { + x: &secret_signed_from_scalar::

(&self.context.gamma), + rho: &self.context.nu, + // Note that the paper does not mention `y` (Elgamal secret) as an input, + // but it is required according to the definition of enc-elg protocol. + a: &self.context.y, + b: &self.context.b, + }, + EncElgPublicInputs { + pk0: pk, + cap_c: &self.r1_echo_broadcast.cap_g.to_precomputed(pk), + cap_a: &self.r1_echo_broadcast.cap_y, + cap_b: &self.r1_echo_broadcast.cap_b1, + cap_x: &self.r1_echo_broadcast.cap_b2, + }, + &self + .context + .aux_info + .public_aux + .safe_get("public aux", destination)? + .rp_params, + &aux, + ); + + Ok(( + DirectMessage::new(serializer, Round1DirectMessage::

{ psi0, psi1 })?, + None, + )) } fn receive_message( @@ -350,72 +410,105 @@ impl Round for Round1 { .deserialize::>(deserializer)?; let echo_broadcast = message .echo_broadcast - .deserialize::>(deserializer)?; + .deserialize::>(deserializer)?; - let aux = (&self.context.ssid_hash, &self.context.my_id); + let aux = (&self.context.epid_hash, &self.context.my_id); - let public_aux = self.public_aux(&self.context.my_id)?; + let public_aux = self.context.public_aux(&self.context.my_id)?; - let from_pk = &self.public_aux(from)?.paillier_pk; + let from_pk = &self.context.public_aux(from)?.paillier_pk; + + let cap_k = echo_broadcast.cap_k.to_precomputed(from_pk); + let cap_g = echo_broadcast.cap_g.to_precomputed(from_pk); if !direct_message.psi0.verify( - EncPublicInputs { + EncElgPublicInputs { + pk0: from_pk, + cap_c: &cap_k, + cap_a: &echo_broadcast.cap_y, + cap_b: &echo_broadcast.cap_a1, + cap_x: &echo_broadcast.cap_a2, + }, + &public_aux.rp_params, + &aux, + ) { + return Err(ReceiveError::protocol(InteractiveSigningError::Round1( + "Failed to verify EncElgProof 0".into(), + ))); + } + + if !direct_message.psi1.verify( + EncElgPublicInputs { pk0: from_pk, - cap_k: &echo_broadcast.cap_k.to_precomputed(from_pk), + cap_c: &cap_g, + cap_a: &echo_broadcast.cap_y, + cap_b: &echo_broadcast.cap_b1, + cap_x: &echo_broadcast.cap_b2, }, &public_aux.rp_params, &aux, ) { return Err(ReceiveError::protocol(InteractiveSigningError::Round1( - "Failed to verify EncProof".into(), + "Failed to verify EncElgProof 1".into(), ))); } Ok(Payload::new(Round1Payload::

{ - cap_k: echo_broadcast.cap_k, - cap_g: echo_broadcast.cap_g, + cap_k, + cap_g, + cap_a1: echo_broadcast.cap_a1, + cap_a2: echo_broadcast.cap_a2, + cap_b1: echo_broadcast.cap_b1, + cap_b2: echo_broadcast.cap_b2, + cap_y: echo_broadcast.cap_y, })) } fn finalize( self, - _rng: &mut impl CryptoRngCore, + rng: &mut impl CryptoRngCore, payloads: BTreeMap, _artifacts: BTreeMap, ) -> Result, LocalError> { - let payloads = payloads.downcast_all::>()?; - - let (others_cap_k, others_cap_g): (BTreeMap<_, _>, BTreeMap<_, _>) = payloads - .into_iter() - .map(|(id, payload)| ((id.clone(), payload.cap_k), (id, payload.cap_g))) - .unzip(); - - let my_id = self.context.my_id.clone(); + let mut payloads = payloads.downcast_all::>()?; - let mut all_cap_k = others_cap_k - .into_iter() - .map(|(id, ciphertext)| { - let paux = self.public_aux(&id)?; - Ok((id, ciphertext.to_precomputed(&paux.paillier_pk))) - }) - .collect::, _>>()?; + let pk = self.context.aux_info.secret_aux.paillier_sk.public_key(); + let my_payload = Round1Payload { + cap_k: self.r1_echo_broadcast.cap_k.to_precomputed(pk), + cap_g: self.r1_echo_broadcast.cap_g.to_precomputed(pk), + cap_a1: self.r1_echo_broadcast.cap_a1, + cap_a2: self.r1_echo_broadcast.cap_a2, + cap_b1: self.r1_echo_broadcast.cap_b1, + cap_b2: self.r1_echo_broadcast.cap_b2, + cap_y: self.r1_echo_broadcast.cap_y, + }; + payloads.insert(self.context.my_id.clone(), my_payload); - let mut all_cap_g = others_cap_g - .into_iter() - .map(|(id, ciphertext)| { - let paux = self.public_aux(&id)?; - let ciphertext_mod = ciphertext.to_precomputed(&paux.paillier_pk); - Ok((id, ciphertext_mod)) - }) - .collect::, _>>()?; + let cap_gamma = self.context.gamma.mul_by_generator(); - all_cap_k.insert(my_id.clone(), self.cap_k); - all_cap_g.insert(my_id, self.cap_g); + let aux = (&self.context.epid_hash, &self.context.my_id); + let psi_elog = ElogProof::new( + rng, + ElogSecretInputs { + y: &self.context.gamma, + lambda: &self.context.b, + }, + // Note that the parameter order in the protocol description and in the ZK proof description do not match. + ElogPublicInputs { + cap_l: &self.r1_echo_broadcast.cap_b1, + cap_m: &self.r1_echo_broadcast.cap_b2, + cap_x: &self.r1_echo_broadcast.cap_y, + cap_y: &cap_gamma, + h: &Point::GENERATOR, + }, + &aux, + ); Ok(FinalizeOutcome::AnotherRound(BoxedRound::new_dynamic(Round2 { context: self.context, - all_cap_k, - all_cap_g, + r1_payloads: payloads, + cap_gamma, + psi_elog, }))) } } @@ -423,30 +516,39 @@ impl Round for Round1 { #[derive(Debug)] struct Round2 { context: Context, - all_cap_k: BTreeMap>, - all_cap_g: BTreeMap>, + r1_payloads: BTreeMap>, + cap_gamma: Point, + psi_elog: ElogProof

, +} + +#[derive(Clone, Serialize, Deserialize)] +#[serde(bound(serialize = " + ElogProof

: Serialize, +"))] +#[serde(bound(deserialize = " + ElogProof

: for<'x> Deserialize<'x>, +"))] +struct Round2NormalBroadcast { + cap_gamma: Point, + psi_elog: ElogProof

, } #[derive(Clone, Serialize, Deserialize)] #[serde(bound(serialize = " CiphertextWire: Serialize, AffGProof

: Serialize, - LogStarProof

: Serialize, "))] #[serde(bound(deserialize = " CiphertextWire: for<'x> Deserialize<'x>, AffGProof

: for<'x> Deserialize<'x>, - LogStarProof

: for<'x> Deserialize<'x>, "))] -struct Round2Message { - cap_gamma: Point, +struct Round2DirectMessage { cap_d: CiphertextWire, hat_cap_d: CiphertextWire, cap_f: CiphertextWire, hat_cap_f: CiphertextWire, psi: AffGProof

, hat_psi: AffGProof

, - hat_psi_prime: LogStarProof

, } #[derive(Debug, Clone)] @@ -490,15 +592,28 @@ impl Round for Round2 { &self.context.other_ids } + fn make_normal_broadcast( + &self, + _rng: &mut impl CryptoRngCore, + serializer: &Serializer, + ) -> Result { + NormalBroadcast::new( + serializer, + Round2NormalBroadcast::

{ + cap_gamma: self.cap_gamma.clone(), + psi_elog: self.psi_elog.clone(), + }, + ) + } + fn make_direct_message( &self, rng: &mut impl CryptoRngCore, serializer: &Serializer, destination: &I, ) -> Result<(DirectMessage, Option), LocalError> { - let aux = (&self.context.ssid_hash, &self.context.my_id); + let aux = (&self.context.epid_hash, &self.context.my_id); - let cap_gamma = self.context.gamma.mul_by_generator(); let pk = self.context.aux_info.secret_aux.paillier_sk.public_key(); let target_pk = &self.context.public_aux(destination)?.paillier_pk; @@ -513,23 +628,15 @@ impl Round for Round2 { let gamma = secret_signed_from_scalar::

(&self.context.gamma); let x = secret_signed_from_scalar::

(self.context.key_share.secret_share()); - let others_cap_k = self - .all_cap_k - .get(destination) - .ok_or(LocalError::new("destination={destination:?} is missing in all_cap_k"))?; + let r1_payload = self.r1_payloads.safe_get("Round 1 payloads", destination)?; let cap_f = Ciphertext::new_with_randomizer(pk, &beta, &r); - let cap_d = others_cap_k * &gamma + Ciphertext::new_with_randomizer(target_pk, &-&beta, &s); + let cap_d = &r1_payload.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 = &r1_payload.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!( - "my_id={:?} is missing in all_cap_g", - &self.context.my_id - )))?; - let rp = &self.context.public_aux(destination)?.rp_params; let psi = AffGProof::new( @@ -543,10 +650,10 @@ impl Round for Round2 { AffGPublicInputs { pk0: target_pk, pk1: pk, - cap_c: others_cap_k, + cap_c: &r1_payload.cap_k, cap_d: &cap_d, cap_y: &cap_f, - cap_x: &cap_gamma, + cap_x: &self.cap_gamma, }, rp, &aux, @@ -563,7 +670,7 @@ impl Round for Round2 { AffGPublicInputs { pk0: target_pk, pk1: pk, - cap_c: others_cap_k, + cap_c: &r1_payload.cap_k, cap_d: &hat_cap_d, cap_y: &hat_cap_f, cap_x: self.context.public_share(&self.context.my_id)?, @@ -572,33 +679,15 @@ impl Round for Round2 { &aux, ); - let hat_psi_prime = LogStarProof::new( - rng, - LogStarSecretInputs { - x: &gamma, - rho: &self.context.nu, - }, - LogStarPublicInputs { - pk0: pk, - cap_c: cap_g, - g: &Point::GENERATOR, - cap_x: &cap_gamma, - }, - rp, - &aux, - ); - let msg = DirectMessage::new( serializer, - Round2Message::

{ - cap_gamma, + Round2DirectMessage::

{ cap_d: cap_d.to_wire(), cap_f: cap_f.to_wire(), hat_cap_d: hat_cap_d.to_wire(), hat_cap_f: hat_cap_f.to_wire(), psi, hat_psi, - hat_psi_prime, }, )?; @@ -625,10 +714,14 @@ impl Round for Round2 { message: ProtocolMessage, ) -> Result> { message.echo_broadcast.assert_is_none()?; - message.normal_broadcast.assert_is_none()?; - let direct_message = message.direct_message.deserialize::>(deserializer)?; + let normal_broadcast = message + .normal_broadcast + .deserialize::>(deserializer)?; + let direct_message = message + .direct_message + .deserialize::>(deserializer)?; - let aux = (&self.context.ssid_hash, from); + let aux = (&self.context.epid_hash, from); let pk = self.context.aux_info.secret_aux.paillier_sk.public_key(); let from_pk = &self.context.public_aux(from)?.paillier_pk; @@ -639,23 +732,17 @@ impl Round for Round2 { let cap_d = direct_message.cap_d.to_precomputed(pk); let hat_cap_d = direct_message.hat_cap_d.to_precomputed(pk); - let my_cap_k = self - .all_cap_k - .get(&self.context.my_id) - .ok_or(LocalError::new("my_id={my_id:?} is missing in all_cap_k"))?; - let cap_g = self - .all_cap_g - .get(from) - .ok_or(LocalError::new("from={from:?} is missing in all_cap_g"))?; + let my_payload = self.r1_payloads.safe_get("Round 1 payloads", &self.context.my_id)?; + let sender_payload = self.r1_payloads.safe_get("Round 1 payloads", from)?; if !direct_message.psi.verify( AffGPublicInputs { pk0: pk, pk1: from_pk, - cap_c: my_cap_k, + cap_c: &my_payload.cap_k, cap_d: &cap_d, cap_y: &direct_message.cap_f.to_precomputed(from_pk), - cap_x: &direct_message.cap_gamma, + cap_x: &normal_broadcast.cap_gamma, }, rp, &aux, @@ -669,7 +756,7 @@ impl Round for Round2 { AffGPublicInputs { pk0: pk, pk1: from_pk, - cap_c: my_cap_k, + cap_c: &my_payload.cap_k, cap_d: &hat_cap_d, cap_y: &direct_message.hat_cap_f.to_precomputed(from_pk), cap_x, @@ -682,34 +769,34 @@ impl Round for Round2 { ))); } - if !direct_message.hat_psi_prime.verify( - LogStarPublicInputs { - pk0: from_pk, - cap_c: cap_g, - g: &Point::GENERATOR, - cap_x: &direct_message.cap_gamma, + if !normal_broadcast.psi_elog.verify( + ElogPublicInputs { + cap_l: &sender_payload.cap_b1, + cap_m: &sender_payload.cap_b2, + cap_x: &sender_payload.cap_y, + cap_y: &normal_broadcast.cap_gamma, + h: &Point::GENERATOR, }, - rp, &aux, ) { return Err(ReceiveError::protocol(InteractiveSigningError::Round2( - "Failed to verify LogStarProof".into(), + "Failed to verify ElogProof".into(), ))); } let alpha = cap_d.decrypt(&self.context.aux_info.secret_aux.paillier_sk); let hat_alpha = hat_cap_d.decrypt(&self.context.aux_info.secret_aux.paillier_sk); - // `alpha == x * y + z` where `0 <= x, y < q`, and `-2^l' <= z <= 2^l'`, + // `alpha == x * y + z` where $x, y ∈ ±q$, and $z ∈ ±2^\ell$`, // where `q` is the curve order. // We will need this bound later, so we're asserting it. let alpha = Option::from(alpha.ensure_bound(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1)) - .ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::OutOfBoundsAlpha))?; + .ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::Round2("invalid alpha bound".into())))?; let hat_alpha = Option::from(hat_alpha.ensure_bound(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1)) - .ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::OutOfBoundsHatAlpha))?; + .ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::Round2("invalid hat_alpha bound".into())))?; Ok(Payload::new(Round2Payload::

{ - cap_gamma: direct_message.cap_gamma, + cap_gamma: normal_broadcast.cap_gamma, alpha, hat_alpha, cap_d, @@ -719,48 +806,66 @@ impl Round for Round2 { fn finalize( self, - _rng: &mut impl CryptoRngCore, + rng: &mut impl CryptoRngCore, payloads: BTreeMap, artifacts: BTreeMap, ) -> Result, LocalError> { let payloads = payloads.downcast_all::>()?; let artifacts = artifacts.downcast_all::>()?; - let cap_gamma = - payloads.values().map(|payload| payload.cap_gamma).sum::() + self.context.gamma.mul_by_generator(); - + let cap_gamma = payloads.values().map(|payload| payload.cap_gamma).sum::() + self.cap_gamma; let cap_delta = cap_gamma * &self.context.k; + let gamma_signed = secret_signed_from_scalar::

(&self.context.gamma); + let x_signed = secret_signed_from_scalar::

(self.context.key_share.secret_share()); + let k_signed = secret_signed_from_scalar::

(&self.context.k); + + // TODO: check if we still need full signed values, or we can just sum scalars let alpha_sum: SecretSigned<_> = payloads.values().map(|payload| &payload.alpha).sum(); let beta_sum: SecretSigned<_> = artifacts.values().map(|artifact| &artifact.beta).sum(); - let delta = secret_signed_from_scalar::

(&self.context.gamma) - * secret_signed_from_scalar::

(&self.context.k) - + &alpha_sum - + &beta_sum; + let delta = gamma_signed * &k_signed + &alpha_sum + &beta_sum; 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()) - * secret_signed_from_scalar::

(&self.context.k) - + &hat_alpha_sum - + &hat_beta_sum; + let chi = x_signed * &k_signed + &hat_alpha_sum + &hat_beta_sum; - let (cap_ds, hat_cap_ds) = payloads - .into_iter() - .map(|(id, payload)| ((id.clone(), payload.cap_d), (id, payload.hat_cap_d))) - .unzip(); + let chi_scalar = secret_scalar_from_signed::

(&chi); + let cap_s = cap_gamma * &chi_scalar; + + let aux = (&self.context.epid_hash, &self.context.my_id); + let my_r1_payload = self.r1_payloads.safe_get("Round 1 payloads", &self.context.my_id)?; + let psi_prime = ElogProof::new( + rng, + ElogSecretInputs { + y: &self.context.k, + lambda: &self.context.a, + }, + // Note that the parameter order in the protocol description and in the ZK proof description do not match. + ElogPublicInputs { + cap_l: &my_r1_payload.cap_a1, + cap_m: &my_r1_payload.cap_a2, + cap_x: &my_r1_payload.cap_y, + cap_y: &cap_delta, + h: &cap_gamma, + }, + &aux, + ); + + let delta_scalar = secret_scalar_from_signed::

(&delta); + + let r3_normal_broadcast = Round3NormalBroadcast { + delta: *delta_scalar.expose_secret(), + cap_s, + cap_delta, + psi_prime, + }; Ok(FinalizeOutcome::AnotherRound(BoxedRound::new_dynamic(Round3 { context: self.context, - delta, - chi, - cap_delta, cap_gamma, - all_cap_k: self.all_cap_k, - all_cap_g: self.all_cap_g, - cap_ds, - hat_cap_ds, - round2_artifacts: artifacts, + chi: *chi_scalar.expose_secret(), + r1_payloads: self.r1_payloads, + r3_normal_broadcast, }))) } } @@ -768,39 +873,26 @@ impl Round for Round2 { #[derive(Debug)] struct Round3 { context: Context, - delta: SecretSigned<::Uint>, - chi: SecretSigned<::Uint>, - cap_delta: Point, cap_gamma: Point, - all_cap_k: BTreeMap>, - all_cap_g: BTreeMap>, - cap_ds: BTreeMap>, - hat_cap_ds: BTreeMap>, - round2_artifacts: BTreeMap>, -} - -impl Round3 { - fn public_aux(&self, i: &I) -> Result<&PublicAuxInfoPrecomputed

, LocalError> { - self.context - .aux_info - .public_aux - .get(i) - .ok_or_else(|| LocalError::new(format!("Missing public_aux for party Id {i:?}"))) - } + chi: Scalar, + r1_payloads: BTreeMap>, + r3_normal_broadcast: Round3NormalBroadcast

, } -#[derive(Clone, Serialize, Deserialize)] -#[serde(bound(serialize = "LogStarProof

: Serialize"))] -#[serde(bound(deserialize = "LogStarProof

: for<'x> Deserialize<'x>"))] -struct Round3Message { - delta: Secret, +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(bound(serialize = "ElogProof

: Serialize"))] +#[serde(bound(deserialize = "ElogProof

: for<'x> Deserialize<'x>"))] +struct Round3NormalBroadcast { + delta: Scalar, + cap_s: Point, cap_delta: Point, - psi_pprime: LogStarProof

, + psi_prime: ElogProof

, } struct Round3Payload { - delta: Secret, + delta: Scalar, cap_delta: Point, + cap_s: Point, } impl Round for Round3 { @@ -822,48 +914,12 @@ impl Round for Round3 { &self.context.other_ids } - fn make_direct_message( + fn make_normal_broadcast( &self, - rng: &mut impl CryptoRngCore, + _rng: &mut impl CryptoRngCore, serializer: &Serializer, - destination: &I, - ) -> Result<(DirectMessage, Option), LocalError> { - let aux = (&self.context.ssid_hash, &self.context.my_id); - let pk = &self.context.aux_info.secret_aux.paillier_sk.public_key(); - - let rp = &self.public_aux(destination)?.rp_params; - - let cap_k = self.all_cap_k.get(&self.context.my_id).ok_or(LocalError::new(format!( - "my_id={:?} is missing in all_cap_k", - &self.context.my_id - )))?; - - let psi_pprime = LogStarProof::new( - rng, - LogStarSecretInputs { - x: &secret_signed_from_scalar::

(&self.context.k), - rho: &self.context.rho, - }, - LogStarPublicInputs { - pk0: pk, - cap_c: cap_k, - g: &self.cap_gamma, - cap_x: &self.cap_delta, - }, - rp, - &aux, - ); - - let dm = DirectMessage::new( - serializer, - Round3Message::

{ - delta: secret_scalar_from_signed::

(&self.delta), - cap_delta: self.cap_delta, - psi_pprime, - }, - )?; - - Ok((dm, None)) + ) -> Result { + NormalBroadcast::new(serializer, self.r3_normal_broadcast.clone()) } fn receive_message( @@ -873,293 +929,101 @@ impl Round for Round3 { message: ProtocolMessage, ) -> Result> { message.echo_broadcast.assert_is_none()?; - message.normal_broadcast.assert_is_none()?; - let direct_message = message.direct_message.deserialize::>(deserializer)?; - - let aux = (&self.context.ssid_hash, &from); - let from_pk = &self.public_aux(from)?.paillier_pk; - - let others_cap_k = self - .all_cap_k - .get(from) - .ok_or(LocalError::new("from={from:?} is missing in all_cap_k"))?; - - let rp = &self.public_aux(&self.context.my_id)?.rp_params; - - if !direct_message.psi_pprime.verify( - LogStarPublicInputs { - pk0: from_pk, - cap_c: others_cap_k, - g: &self.cap_gamma, - cap_x: &direct_message.cap_delta, + message.direct_message.assert_is_none()?; + let normal_broadcast = message + .normal_broadcast + .deserialize::>(deserializer)?; + + let aux = (&self.context.epid_hash, from); + let r1_payload = self.r1_payloads.safe_get("Round 1 payload", from)?; + + if !normal_broadcast.psi_prime.verify( + ElogPublicInputs { + cap_l: &r1_payload.cap_a1, + cap_m: &r1_payload.cap_a2, + cap_x: &r1_payload.cap_y, + cap_y: &normal_broadcast.cap_delta, + h: &self.cap_gamma, }, - rp, &aux, ) { return Err(ReceiveError::protocol(InteractiveSigningError::Round3( - "Failed to verify Log-Star proof".into(), + "Failed to verify ElogProof".into(), ))); } + Ok(Payload::new(Round3Payload { - delta: direct_message.delta, - cap_delta: direct_message.cap_delta, + delta: normal_broadcast.delta, + cap_delta: normal_broadcast.cap_delta, + cap_s: normal_broadcast.cap_s, })) } fn finalize( self, - rng: &mut impl CryptoRngCore, + _rng: &mut impl CryptoRngCore, payloads: BTreeMap, _artifacts: BTreeMap, ) -> Result, LocalError> { - let payloads = payloads.downcast_all::()?; - - let (deltas, cap_deltas): (BTreeMap<_, _>, BTreeMap<_, _>) = payloads - .into_iter() - .map(|(id, payload)| ((id.clone(), payload.delta), (id, payload.cap_delta))) - .unzip(); - - let scalar_delta = secret_scalar_from_signed::

(&self.delta); - let assembled_delta: Secret = &scalar_delta + deltas.values().sum::>(); - let assembled_cap_delta: Point = self.cap_delta + cap_deltas.values().sum(); - - if assembled_delta.mul_by_generator() == assembled_cap_delta { - let inv_delta = assembled_delta.invert().ok_or_else(|| { - LocalError::new(concat![ - "The assembled delta is zero. ", - "Either all other nodes are malicious, or it's a freak accident. ", - "Restart the protocol." - ]) - })?; - let nonce = (self.cap_gamma * inv_delta).x_coordinate(); - let my_id = self.context.my_id.clone(); - - let values = self - .round2_artifacts - .into_iter() - .map(|(id, artifact)| { - let cap_k = self - .all_cap_k - .get(&id) - .ok_or_else(|| LocalError::new("id={id:?} is missing in all_cap_k"))? - .clone(); - let hat_cap_d_received = self - .hat_cap_ds - .get(&id) - .ok_or_else(|| LocalError::new("id={id:?} is missing in hat_cap_ds"))? - .clone(); - let values = PresigningValues { - hat_beta: artifact.hat_beta, - hat_r: artifact.hat_r, - hat_s: artifact.hat_s, - cap_k, - hat_cap_d_received, - hat_cap_d: artifact.hat_cap_d, - hat_cap_f: artifact.hat_cap_f, - }; - Ok((id, values)) - }) - .collect::>()?; - - let presigning_data = PresigningData { - nonce, - ephemeral_scalar_share: self.context.k.clone(), - product_share: secret_scalar_from_signed::

(&self.chi), - product_share_nonreduced: self.chi, - cap_k: self - .all_cap_k - .get(&my_id) - .ok_or_else(|| LocalError::new("m_id={my_id:?} is missing in all_cap_k"))? - .clone(), - values, - }; - - return Ok(FinalizeOutcome::AnotherRound(BoxedRound::new_dynamic(Round4::new( - self.context, - presigning_data, - )))); + let mut payloads = payloads.downcast_all::()?; + let my_payload = Round3Payload { + delta: self.r3_normal_broadcast.delta, + cap_delta: self.r3_normal_broadcast.cap_delta, + cap_s: self.r3_normal_broadcast.cap_s, + }; + payloads.insert(self.context.my_id.clone(), my_payload); + + let delta = payloads.values().map(|payload| payload.delta).sum::(); + let cap_delta = payloads.values().map(|payload| payload.cap_delta).sum(); + + if delta.mul_by_generator() != cap_delta { + unimplemented!(); } - // Construct the correctness proofs - - let sk = &self.context.aux_info.secret_aux.paillier_sk; - let pk = sk.public_key(); + let cap_s = payloads.values().map(|payload| payload.cap_s).sum::(); + let cap_x = self.context.key_share.verifying_key_as_point(); - let aux = (&self.context.ssid_hash, &self.context.my_id); - - // Aff-g proofs - - let mut aff_g_proofs = Vec::new(); - - let cap_gamma = self.context.gamma.mul_by_generator(); - - for (id_j, (_, r2_artifacts)) in self.context.other_ids.iter().zip(self.round2_artifacts.iter()) { - let cap_c = self - .all_cap_k - .get(id_j) - .ok_or_else(|| LocalError::new("id_j={id_j:?} is missing in all_cap_k"))?; - for id_l in self.context.other_ids.iter().filter(|id| *id != id_j) { - let paux = self.public_aux(id_j)?; - let target_pk = &paux.paillier_pk; - let rp = &paux.rp_params; - - let beta = &r2_artifacts.beta; - let r = &r2_artifacts.r; - let s = &r2_artifacts.s; - - let p_aff_g = AffGProof::

::new( - rng, - AffGSecretInputs { - x: &secret_signed_from_scalar::

(&self.context.gamma), - y: beta, - rho: s, - rho_y: r, - }, - AffGPublicInputs { - pk0: target_pk, - pk1: pk, - cap_c, - cap_d: &r2_artifacts.cap_d, - cap_y: &r2_artifacts.cap_f, - cap_x: &cap_gamma, - }, - rp, - &aux, - ); - - assert!(p_aff_g.verify( - AffGPublicInputs { - pk0: target_pk, - pk1: pk, - cap_c, - cap_d: &r2_artifacts.cap_d, - cap_y: &r2_artifacts.cap_f, - cap_x: &cap_gamma - }, - rp, - &aux, - )); - - aff_g_proofs.push((id_j.clone(), id_l.clone(), p_aff_g)); - } - } - - // Mul proof - let my_id = &self.context.my_id; - let rho = Randomizer::random(rng, pk); - let cap_k = self - .all_cap_k - .get(my_id) - .ok_or_else(|| LocalError::new("my_id={my_id:?} is missing in all_cap_k"))?; - let cap_g = self - .all_cap_g - .get(my_id) - .ok_or_else(|| LocalError::new("my_id={my_id:?} is missing in all_cap_g"))?; - let cap_h = (cap_g * &secret_signed_from_scalar::

(&self.context.k)).mul_randomizer(&rho); - - let p_mul = MulProof::

::new( - rng, - MulSecretInputs { - x: &secret_signed_from_scalar::

(&self.context.k), - rho_x: &self.context.rho, - rho: &rho, - }, - MulPublicInputs { - pk, - cap_x: cap_k, - cap_y: cap_g, - cap_c: &cap_h, - }, - &aux, - ); - assert!(p_mul.verify( - MulPublicInputs { - pk, - cap_x: cap_k, - cap_y: cap_g, - cap_c: &cap_h - }, - &aux - )); - - // Dec proof - - let mut ciphertext = cap_h.clone(); - - for id_j in self.context.other_ids.iter() { - let cap_d = self - .cap_ds - .get(id_j) - .ok_or_else(|| LocalError::new(format!("Missing `D` for {id_j:?}")))?; - let artifact_j = self - .round2_artifacts - .get(id_j) - .ok_or_else(|| LocalError::new(format!("Missing Round 2 artifact for {id_j:?}")))?; - ciphertext = ciphertext + cap_d + &artifact_j.cap_f; - } - - let rho = ciphertext.derive_randomizer(sk); - - let mut dec_proofs = Vec::new(); - for id_j in self.context.other_ids.iter() { - let p_dec = DecProof::

::new( - rng, - DecSecretInputs { - y: &self.delta, - rho: &rho, - }, - DecPublicInputs { - pk0: pk, - x: scalar_delta.expose_secret(), - cap_c: &ciphertext, - }, - &self.public_aux(id_j)?.rp_params, - &aux, - ); - assert!(p_dec.verify( - DecPublicInputs { - pk0: pk, - x: scalar_delta.expose_secret(), - cap_c: &ciphertext - }, - &self.public_aux(id_j)?.rp_params, - &aux - )); - dec_proofs.push((id_j.clone(), p_dec)); + if cap_s != cap_x * delta { + unimplemented!(); } - unimplemented!() + let delta_inv = delta.invert().unwrap(); + + // TODO: this whole thing is probably supposed to be secret? + let presigning_data = PresigningData { + cap_gamma: self.cap_gamma, + tilde_k: *self.context.k.expose_secret() * delta_inv, + tilde_chi: self.chi * delta_inv, + tilde_cap_deltas: payloads + .iter() + .map(|(id, payload)| (id.clone(), payload.cap_delta * delta_inv)) + .collect(), + tilde_cap_ss: payloads + .iter() + .map(|(id, payload)| (id.clone(), payload.cap_s * delta_inv)) + .collect(), + }; + + let nonce = presigning_data.cap_gamma.x_coordinate(); + let sigma = presigning_data.tilde_k * self.context.scalar_message + nonce * presigning_data.tilde_chi; + + Ok(FinalizeOutcome::AnotherRound(BoxedRound::new_dynamic(Round4 { + context: self.context, + presigning_data, + sigma, + }))) } } #[derive(Debug)] struct Round4 { context: Context, - presigning: PresigningData, - r: Scalar, + presigning_data: PresigningData, sigma: Scalar, } -impl Round4 -where - P: SchemeParams, - I: PartyId, -{ - fn new(context: Context, presigning: PresigningData) -> Self { - let r = presigning.nonce; - let sigma = - *(&presigning.ephemeral_scalar_share * context.message + &presigning.product_share * r).expose_secret(); - Self { - context, - presigning, - r, - sigma, - } - } -} - #[derive(Clone, Serialize, Deserialize)] -pub(super) struct Round4Message { +pub(super) struct Round4NormalBroadcast { pub(crate) sigma: Scalar, } @@ -1175,7 +1039,7 @@ impl Round for Round4 { } fn possible_next_rounds(&self) -> BTreeSet { - [5.into()].into() + [].into() } fn may_produce_result(&self) -> bool { @@ -1195,7 +1059,7 @@ impl Round for Round4 { _rng: &mut impl CryptoRngCore, serializer: &Serializer, ) -> Result { - NormalBroadcast::new(serializer, Round4Message { sigma: self.sigma }) + NormalBroadcast::new(serializer, Round4NormalBroadcast { sigma: self.sigma }) } fn receive_message( @@ -1206,7 +1070,9 @@ impl Round for Round4 { ) -> Result> { message.echo_broadcast.assert_is_none()?; message.direct_message.assert_is_none()?; - let normal_broadcast = message.normal_broadcast.deserialize::(deserializer)?; + let normal_broadcast = message + .normal_broadcast + .deserialize::(deserializer)?; Ok(Payload::new(Round4Payload { sigma: normal_broadcast.sigma, @@ -1215,7 +1081,7 @@ impl Round for Round4 { fn finalize( self, - rng: &mut impl CryptoRngCore, + _rng: &mut impl CryptoRngCore, payloads: BTreeMap, _artifacts: BTreeMap, ) -> Result, LocalError> { @@ -1224,238 +1090,17 @@ impl Round for Round4 { let assembled_sigma = payloads.values().map(|payload| payload.sigma).sum::() + self.sigma; let signature = RecoverableSignature::from_scalars( - &self.r, + &self.presigning_data.cap_gamma.x_coordinate(), &assembled_sigma, &self.context.key_share.verifying_key_as_point(), - &self.context.message, + &self.context.scalar_message, ); if let Some(signature) = signature { return Ok(FinalizeOutcome::Result(signature)); } - let my_id = self.context.my_id.clone(); - let aux = (&self.context.ssid_hash, &my_id); - - let sk = &self.context.aux_info.secret_aux.paillier_sk; - let pk = sk.public_key(); - - // Aff-g proofs - - let mut aff_g_proofs = Vec::new(); - - for id_j in self.context.other_ids.iter() { - for id_l in self.context.other_ids.iter().filter(|id| *id != id_j) { - let target_pk = &self.context.public_aux(id_j)?.paillier_pk; - let rp = &self.context.public_aux(id_l)?.rp_params; - - let values = self - .presigning - .values - .get(id_j) - .ok_or_else(|| LocalError::new("Missing presigning values for {id_j:?}"))?; - - let p_aff_g = AffGProof::

::new( - rng, - AffGSecretInputs { - x: &secret_signed_from_scalar::

(self.context.key_share.secret_share()), - y: &values.hat_beta, - rho: &values.hat_s, - rho_y: &values.hat_r, - }, - AffGPublicInputs { - pk0: target_pk, - pk1: pk, - cap_c: &values.cap_k, - cap_d: &values.hat_cap_d, - cap_y: &values.hat_cap_f, - cap_x: self.context.public_share(&my_id)?, - }, - rp, - &aux, - ); - - assert!(p_aff_g.verify( - AffGPublicInputs { - pk0: target_pk, - pk1: pk, - cap_c: &values.cap_k, - cap_d: &values.hat_cap_d, - cap_y: &values.hat_cap_f, - cap_x: self.context.public_share(&my_id)? - }, - rp, - &aux, - )); - - aff_g_proofs.push((id_j.clone(), id_l.clone(), p_aff_g)); - } - } - - // mul* proofs - - let x = &self.context.key_share.secret_share(); - let cap_x = self.context.public_share(&my_id)?; - - let rho = Randomizer::random(rng, pk); - let hat_cap_h = (&self.presigning.cap_k * &secret_signed_from_scalar::

(x)).mul_randomizer(&rho); - - let aux = (&self.context.ssid_hash, &my_id); - - let mut mul_star_proofs = Vec::new(); - - for id_l in self.context.other_ids.iter() { - let paux = self.context.public_aux(id_l)?; - let p_mul = MulStarProof::

::new( - rng, - MulStarSecretInputs { - x: &secret_signed_from_scalar::

(x), - rho: &rho, - }, - MulStarPublicInputs { - pk0: pk, - cap_c: &self.presigning.cap_k, - cap_d: &hat_cap_h, - cap_x, - }, - &paux.rp_params, - &aux, - ); - - assert!(p_mul.verify( - MulStarPublicInputs { - pk0: pk, - cap_c: &self.presigning.cap_k, - cap_d: &hat_cap_h, - cap_x - }, - &paux.rp_params, - &aux, - )); - - mul_star_proofs.push((id_l.clone(), p_mul)); - } - - // dec proofs - - let mut ciphertext = hat_cap_h.clone(); - for id_j in self.context.other_ids.iter() { - let values = &self - .presigning - .values - .get(id_j) - .ok_or_else(|| LocalError::new(format!("Missing presigning values for {id_j:?}")))?; - ciphertext = ciphertext + &values.hat_cap_d_received + &values.hat_cap_f; - } - - let r = self.presigning.nonce; - let signed_r = public_signed_from_scalar::

(&r); - let signed_message = public_signed_from_scalar::

(&self.context.message); - - let ciphertext = ciphertext * &signed_r + &self.presigning.cap_k * &signed_message; - - let rho = ciphertext.derive_randomizer(sk); - // This is the same as `s_part` but if all the calculations were performed - // without reducing modulo curve order. - let s_part_nonreduced = secret_signed_from_scalar::

(&self.presigning.ephemeral_scalar_share) - * signed_message - + &self.presigning.product_share_nonreduced * signed_r; - - let mut dec_proofs = Vec::new(); - for id_l in self.context.other_ids.iter() { - let paux = self.context.public_aux(id_l)?; - let p_dec = DecProof::

::new( - rng, - DecSecretInputs { - y: &s_part_nonreduced, - rho: &rho, - }, - DecPublicInputs { - pk0: pk, - x: &self.sigma, - cap_c: &ciphertext, - }, - &paux.rp_params, - &aux, - ); - assert!(p_dec.verify( - DecPublicInputs { - pk0: pk, - x: &self.sigma, - cap_c: &ciphertext - }, - &paux.rp_params, - &aux, - )); - dec_proofs.push((id_l.clone(), p_dec)); - } - - Ok(FinalizeOutcome::AnotherRound(BoxedRound::new_dynamic( - SigningErrorRound { context: self.context }, - ))) - } -} - -#[derive(Debug)] -struct SigningErrorRound { - context: Context, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct SigningErrorMessage(PhantomData<(P, I)>); - -impl Round for SigningErrorRound { - type Protocol = InteractiveSigningProtocol; - - fn id(&self) -> RoundId { - 5.into() - } - - fn possible_next_rounds(&self) -> BTreeSet { - [].into() - } - - fn message_destinations(&self) -> &BTreeSet { - &self.context.other_ids - } - - fn expecting_messages_from(&self) -> &BTreeSet { - &self.context.other_ids - } - - fn make_echo_broadcast( - &self, - _rng: &mut impl CryptoRngCore, - serializer: &Serializer, - ) -> Result { - EchoBroadcast::new(serializer, SigningErrorMessage::(PhantomData)) - } - - fn receive_message( - &self, - deserializer: &Deserializer, - _from: &I, - message: ProtocolMessage, - ) -> Result> { - message.normal_broadcast.assert_is_none()?; - message.direct_message.assert_is_none()?; - let _echo_broadcast = message - .echo_broadcast - .deserialize::>(deserializer)?; - Err(ReceiveError::protocol(InteractiveSigningError::SigningError( - "Signing error stub".into(), - ))) - } - - fn finalize( - self, - _rng: &mut impl CryptoRngCore, - _payloads: BTreeMap, - _artifacts: BTreeMap, - ) -> Result, LocalError> { - Err(LocalError::new( - "One of the messages should have been missing or invalid", - )) + Err(LocalError::new("Failed!")) } } diff --git a/synedrion/src/cggmp21/sigma.rs b/synedrion/src/cggmp21/sigma.rs index 4ea22ac..868e345 100644 --- a/synedrion/src/cggmp21/sigma.rs +++ b/synedrion/src/cggmp21/sigma.rs @@ -17,7 +17,9 @@ mod sch; pub(crate) use aff_g::{AffGProof, AffGPublicInputs, AffGSecretInputs}; pub(crate) use dec::{DecProof, DecPublicInputs, DecSecretInputs}; +pub(crate) use elog::{ElogProof, ElogPublicInputs, ElogSecretInputs}; pub(crate) use enc::{EncProof, EncPublicInputs, EncSecretInputs}; +pub(crate) use enc_elg::{EncElgProof, EncElgPublicInputs, EncElgSecretInputs}; pub(crate) use fac::FacProof; pub(crate) use log_star::{LogStarProof, LogStarPublicInputs, LogStarSecretInputs}; pub(crate) use mod_::ModProof;