diff --git a/crypto/dleq/Cargo.toml b/crypto/dleq/Cargo.toml index de5338b7..27a806e8 100644 --- a/crypto/dleq/Cargo.toml +++ b/crypto/dleq/Cargo.toml @@ -10,6 +10,8 @@ edition = "2021" thiserror = "1" rand_core = "0.6" +subtle = "2.4" + transcript = { package = "flexible-transcript", path = "../transcript", version = "0.1" } ff = "0.12" diff --git a/crypto/dleq/src/cross_group/mod.rs b/crypto/dleq/src/cross_group/mod.rs index 012d1138..8026bafe 100644 --- a/crypto/dleq/src/cross_group/mod.rs +++ b/crypto/dleq/src/cross_group/mod.rs @@ -1,6 +1,8 @@ use thiserror::Error; use rand_core::{RngCore, CryptoRng}; +use subtle::{Choice, ConditionallySelectable}; + use transcript::Transcript; use group::{ff::{Field, PrimeField, PrimeFieldBits}, prime::PrimeGroup}; @@ -197,6 +199,9 @@ impl DLEqProof let capacity = usize::try_from(G0::Scalar::CAPACITY.min(G1::Scalar::CAPACITY)).unwrap(); let mut bits = Vec::with_capacity(capacity); for (i, bit) in raw_bits.iter().enumerate() { + let bit = *bit as u8; + debug_assert_eq!(bit | 1, 1); + let last = i == (capacity - 1); let blinding_key = ( Self::blinding_key(&mut *rng, &mut blinding_key_total.0, &mut pow_2.0, last), @@ -211,11 +216,8 @@ impl DLEqProof (generators.0.alt * blinding_key.0), (generators.1.alt * blinding_key.1) ); - // TODO: Not constant time - if *bit { - commitments.0 += generators.0.primary; - commitments.1 += generators.1.primary; - } + commitments.0 += generators.0.primary * G0::Scalar::from(bit.into()); + commitments.1 += generators.1.primary * G1::Scalar::from(bit.into()); Self::transcript_bit(transcript, i, commitments); let nonces = (G0::Scalar::random(&mut *rng), G1::Scalar::random(&mut *rng)); @@ -223,29 +225,22 @@ impl DLEqProof transcript.clone(), ((generators.0.alt * nonces.0), (generators.1.alt * nonces.1)) ); - let s_0 = (G0::Scalar::random(&mut *rng), G1::Scalar::random(&mut *rng)); + let mut s_0 = (G0::Scalar::random(&mut *rng), G1::Scalar::random(&mut *rng)); - let e_1 = Self::R_nonces( - transcript.clone(), - generators, - (s_0.0, s_0.1), - if *bit { - commitments - } else { - ((commitments.0 - generators.0.primary), (commitments.1 - generators.1.primary)) - }, - e_0 - ); - let s_1 = (nonces.0 + (e_1.0 * blinding_key.0), nonces.1 + (e_1.1 * blinding_key.1)); + let mut to_sign = commitments; + let bit = Choice::from(bit); + let inv_bit = (!bit).unwrap_u8(); + to_sign.0 -= generators.0.primary * G0::Scalar::from(inv_bit.into()); + to_sign.1 -= generators.1.primary * G1::Scalar::from(inv_bit.into()); + let e_1 = Self::R_nonces(transcript.clone(), generators, (s_0.0, s_0.1), to_sign, e_0); + let mut s_1 = (nonces.0 + (e_1.0 * blinding_key.0), nonces.1 + (e_1.1 * blinding_key.1)); - bits.push( - if *bit { - Bit { commitments, e: e_0.0, s: [s_1, s_0] } - } else { - Bit { commitments, e: e_1.0, s: [s_0, s_1] } - } - ); + let e = G0::Scalar::conditional_select(&e_1.0, &e_0.0, bit); + G0::Scalar::conditional_swap(&mut s_1.0, &mut s_0.0, bit); + G1::Scalar::conditional_swap(&mut s_1.1, &mut s_0.1, bit); + bits.push(Bit { commitments, e, s: [s_0, s_1] }); + // Break in order to not generate commitments for unused bits if last { break; }