From 4eafbe2a09065268ef39c72f2a82c9aec9274487 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Thu, 30 Jun 2022 11:23:13 -0400 Subject: [PATCH] Unify the cross-group DLEq challenges This does reduce the strength of the challenges to that of the weaker field, yet that doesn't have any impact on whether or not this is ZK due to the key being shared across fields. Saves ~8kb. --- crypto/dleq/src/cross_group/mod.rs | 23 ++++++++++++----------- crypto/dleq/src/cross_group/schnorr.rs | 2 +- crypto/dleq/src/lib.rs | 9 +++------ 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/crypto/dleq/src/cross_group/mod.rs b/crypto/dleq/src/cross_group/mod.rs index 498d5f9f..012d1138 100644 --- a/crypto/dleq/src/cross_group/mod.rs +++ b/crypto/dleq/src/cross_group/mod.rs @@ -8,7 +8,7 @@ use group::{ff::{Field, PrimeField, PrimeFieldBits}, prime::PrimeGroup}; use crate::{Generators, challenge}; pub mod scalar; -use scalar::scalar_normalize; +use scalar::{scalar_normalize, scalar_convert}; pub(crate) mod schnorr; use schnorr::SchnorrPoK; @@ -32,7 +32,7 @@ pub(crate) fn read_point(r: &mut R) -> std::io::Result { commitments: (G0, G1), - e: (G0::Scalar, G1::Scalar), + e: G0::Scalar, s: [(G0::Scalar, G1::Scalar); 2] } @@ -41,8 +41,7 @@ impl Bit { pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { w.write_all(self.commitments.0.to_bytes().as_ref())?; w.write_all(self.commitments.1.to_bytes().as_ref())?; - w.write_all(self.e.0.to_repr().as_ref())?; - w.write_all(self.e.1.to_repr().as_ref())?; + w.write_all(self.e.to_repr().as_ref())?; for i in 0 .. 2 { w.write_all(self.s[i].0.to_repr().as_ref())?; w.write_all(self.s[i].1.to_repr().as_ref())?; @@ -55,7 +54,7 @@ impl Bit { Ok( Bit { commitments: (read_point(r)?, read_point(r)?), - e: (read_scalar(r)?, read_scalar(r)?), + e: read_scalar(r)?, s: [ (read_scalar(r)?, read_scalar(r)?), (read_scalar(r)?, read_scalar(r)?) @@ -71,6 +70,8 @@ pub enum DLEqError { InvalidProofOfKnowledge, #[error("invalid proof length")] InvalidProofLength, + #[error("invalid challenge")] + InvalidChallenge, #[error("invalid proof")] InvalidProof } @@ -117,7 +118,7 @@ impl DLEqProof fn nonces(mut transcript: T, nonces: (G0, G1)) -> (G0::Scalar, G1::Scalar) { transcript.append_message(b"nonce_0", nonces.0.to_bytes().as_ref()); transcript.append_message(b"nonce_1", nonces.1.to_bytes().as_ref()); - (challenge(&mut transcript, b"challenge_G"), challenge(&mut transcript, b"challenge_H")) + scalar_normalize(challenge(&mut transcript)) } #[allow(non_snake_case)] @@ -134,7 +135,6 @@ impl DLEqProof ) } - // TODO: Use multiexp here after https://github.com/serai-dex/serai/issues/17 fn reconstruct_key( commitments: impl Iterator ) -> G where G::Scalar: PrimeFieldBits { @@ -240,9 +240,9 @@ impl DLEqProof bits.push( if *bit { - Bit { commitments, e: e_0, s: [s_1, s_0] } + Bit { commitments, e: e_0.0, s: [s_1, s_0] } } else { - Bit { commitments, e: e_1, s: [s_0, s_1] } + Bit { commitments, e: e_1.0, s: [s_0, s_1] } } ); @@ -282,7 +282,8 @@ impl DLEqProof for (i, bit) in self.bits.iter().enumerate() { Self::transcript_bit(transcript, i, bit.commitments); - if bit.e != Self::R_nonces( + let bit_e = (bit.e, scalar_convert(bit.e).ok_or(DLEqError::InvalidChallenge)?); + if bit_e != Self::R_nonces( transcript.clone(), generators, bit.s[0], @@ -295,7 +296,7 @@ impl DLEqProof generators, bit.s[1], bit.commitments, - bit.e + bit_e ) ) { return Err(DLEqError::InvalidProof); diff --git a/crypto/dleq/src/cross_group/schnorr.rs b/crypto/dleq/src/cross_group/schnorr.rs index cbb7cfc8..cbd60aa6 100644 --- a/crypto/dleq/src/cross_group/schnorr.rs +++ b/crypto/dleq/src/cross_group/schnorr.rs @@ -28,7 +28,7 @@ impl SchnorrPoK { transcript.append_message(b"generator", generator.to_bytes().as_ref()); transcript.append_message(b"nonce", R.to_bytes().as_ref()); transcript.append_message(b"public_key", A.to_bytes().as_ref()); - challenge(transcript, b"challenge") + challenge(transcript) } pub(crate) fn prove( diff --git a/crypto/dleq/src/lib.rs b/crypto/dleq/src/lib.rs index cc15775e..f960cdfe 100644 --- a/crypto/dleq/src/lib.rs +++ b/crypto/dleq/src/lib.rs @@ -33,10 +33,7 @@ impl Generators { } } -pub(crate) fn challenge( - transcript: &mut T, - label: &'static [u8] -) -> F { +pub(crate) fn challenge(transcript: &mut T) -> F { assert!(F::NUM_BITS <= 384); // From here, there are three ways to get a scalar under the ff/group API @@ -44,7 +41,7 @@ pub(crate) fn challenge( // 2: Grabbing a UInt library to perform reduction by the modulus, then determining endianess // and loading it in // 3: Iterating over each byte and manually doubling/adding. This is simplest - let challenge_bytes = transcript.challenge(label); + let challenge_bytes = transcript.challenge(b"challenge"); assert!(challenge_bytes.as_ref().len() == 64); let mut challenge = F::zero(); @@ -94,7 +91,7 @@ impl DLEqProof { transcript.append_message(b"nonce_alternate", nonces.1.to_bytes().as_ref()); transcript.append_message(b"point_primary", points.0.to_bytes().as_ref()); transcript.append_message(b"point_alternate", points.1.to_bytes().as_ref()); - challenge(transcript, b"challenge") + challenge(transcript) } pub fn prove(