Skip to content

Commit

Permalink
Bit bounds in crypto-bigint use u32 now
Browse files Browse the repository at this point in the history
  • Loading branch information
fjarri committed Nov 27, 2024
1 parent 551cd54 commit e3cbb41
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 71 deletions.
4 changes: 2 additions & 2 deletions synedrion/src/cggmp21/interactive_signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,10 +608,10 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round2<P, I> {
// where `q` is the curve order.
// We will need this bound later, so we're asserting it.
let alpha = alpha
.assert_bit_bound_usize(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1)
.assert_bit_bound(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1)
.ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::OutOfBoundsAlpha))?;
let hat_alpha = hat_alpha
.assert_bit_bound_usize(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1)
.assert_bit_bound(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1)
.ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::OutOfBoundsHatAlpha))?;

Ok(Payload::new(Round2Payload::<P> {
Expand Down
22 changes: 11 additions & 11 deletions synedrion/src/cggmp21/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl PaillierParams for PaillierTest {
are much smaller than 2*PRIME_BITS.
*/

const PRIME_BITS: usize = 397;
const PRIME_BITS: u32 = 397;
type HalfUint = U512;
type HalfUintMod = U512Mod;
type Uint = U1024;
Expand All @@ -91,7 +91,7 @@ impl PaillierParams for PaillierTest {
pub struct PaillierProduction;

impl PaillierParams for PaillierProduction {
const PRIME_BITS: usize = 1024;
const PRIME_BITS: u32 = 1024;
type HalfUint = U1024;
type HalfUintMod = U1024Mod;
type Uint = U2048;
Expand All @@ -112,11 +112,11 @@ pub trait SchemeParams: Debug + Clone + Send + PartialEq + Eq + Send + Sync + 's
/// The scheme's statistical security parameter.
const SECURITY_PARAMETER: usize; // $\kappa$
/// The bound for secret values.
const L_BOUND: usize; // $\ell$, paper sets it to $\log2(q)$ (see Table 2)
const L_BOUND: u32; // $\ell$, paper sets it to $\log2(q)$ (see Table 2)
/// The error bound for secret masks.
const LP_BOUND: usize; // $\ell^\prime$, in paper $= 5 \ell$ (see Table 2)
const LP_BOUND: u32; // $\ell^\prime$, in paper $= 5 \ell$ (see Table 2)
/// The error bound for range checks (referred to in the paper as the slackness parameter).
const EPS_BOUND: usize; // $\eps$, in paper $= 2 \ell$ (see Table 2)
const EPS_BOUND: u32; // $\eps$, in paper $= 2 \ell$ (see Table 2)
/// The parameters of the Paillier encryption.
///
/// Note: `PaillierParams::Uint` must be able to contain the full range of `Scalar` values
Expand Down Expand Up @@ -213,9 +213,9 @@ pub struct TestParams;
// - P^{fac} assumes $N ~ 2^{4 \ell + 2 \eps}$
impl SchemeParams for TestParams {
const SECURITY_PARAMETER: usize = 10;
const L_BOUND: usize = 256;
const LP_BOUND: usize = 256;
const EPS_BOUND: usize = 320;
const L_BOUND: u32 = 256;
const LP_BOUND: u32 = 256;
const EPS_BOUND: u32 = 320;
type Paillier = PaillierTest;
const CURVE_ORDER: NonZero<<Self::Paillier as PaillierParams>::Uint> = convert_uint(upcast_uint(ORDER))
.to_nz()
Expand All @@ -231,9 +231,9 @@ pub struct ProductionParams;

impl SchemeParams for ProductionParams {
const SECURITY_PARAMETER: usize = 80; // The value is given in Table 2 in the paper
const L_BOUND: usize = 256;
const LP_BOUND: usize = Self::L_BOUND * 5;
const EPS_BOUND: usize = Self::L_BOUND * 2;
const L_BOUND: u32 = 256;
const LP_BOUND: u32 = Self::L_BOUND * 5;
const EPS_BOUND: u32 = Self::L_BOUND * 2;
type Paillier = PaillierProduction;
const CURVE_ORDER: NonZero<<Self::Paillier as PaillierParams>::Uint> = convert_uint(upcast_uint(ORDER))
.to_nz()
Expand Down
2 changes: 1 addition & 1 deletion synedrion/src/cggmp21/sigma/fac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<P: SchemeParams> FacProof<P> {
// `z1` and `z2` during verification.
let sqrt_cap_n = Bounded::new(
<P::Paillier as PaillierParams>::Uint::one() << (<P::Paillier as PaillierParams>::PRIME_BITS - 2),
<P::Paillier as PaillierParams>::PRIME_BITS as u32,
<P::Paillier as PaillierParams>::PRIME_BITS,
)
.expect("the value is bounded by `2^PRIME_BITS` by construction");

Expand Down
7 changes: 2 additions & 5 deletions synedrion/src/cggmp21/sigma/mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,8 @@ impl<P: SchemeParams> MulProof<P> {
let r_mod = Randomizer::random(rng, pk);
let s_mod = Randomizer::random(rng, pk);

let alpha = Bounded::new(
alpha_mod.retrieve(),
<P::Paillier as PaillierParams>::MODULUS_BITS as u32,
)
.expect("the value is bounded by `MODULUS_BITS` by construction");
let alpha = Bounded::new(alpha_mod.retrieve(), <P::Paillier as PaillierParams>::MODULUS_BITS)
.expect("the value is bounded by `MODULUS_BITS` by construction");
let r = r_mod.to_wire();
let s = s_mod.to_wire();

Expand Down
12 changes: 5 additions & 7 deletions synedrion/src/paillier/encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ impl<P: PaillierParams> Ciphertext<P> {

let mut result = Signed::new_from_unsigned(
P::Uint::conditional_select(&positive_result, &negative_result, is_negative),
P::MODULUS_BITS as u32 - 1,
P::MODULUS_BITS - 1,
)
.expect("the value is within `[-2^(MODULUS_BITS-1), 2^(MODULUS_BITS-1)]` by construction");

Expand Down Expand Up @@ -419,7 +419,7 @@ mod tests {
} else {
result
};
let mut signed_result = Signed::new_from_unsigned(twos_complement_result, P::MODULUS_BITS as u32 - 1).unwrap();
let mut signed_result = Signed::new_from_unsigned(twos_complement_result, P::MODULUS_BITS - 1).unwrap();
signed_result.conditional_negate(val.is_negative());
signed_result
}
Expand All @@ -442,8 +442,7 @@ mod tests {
fn signed_roundtrip() {
let sk = SecretKeyPaillierWire::<PaillierTest>::random(&mut OsRng).into_precomputed();
let pk = sk.public_key();
let plaintext =
Signed::random_bounded_bits(&mut OsRng, <PaillierTest as PaillierParams>::Uint::BITS as usize - 2);
let plaintext = Signed::random_bounded_bits(&mut OsRng, <PaillierTest as PaillierParams>::Uint::BITS - 2);
let ciphertext = Ciphertext::new_signed(&mut OsRng, pk, &plaintext);
let plaintext_back = ciphertext.decrypt_signed(&sk);
let plaintext_reduced = reduce::<PaillierTest>(&plaintext, &pk.modulus_nonzero());
Expand All @@ -468,7 +467,7 @@ mod tests {
let plaintext = <PaillierTest as PaillierParams>::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero());
let ciphertext = Ciphertext::<PaillierTest>::new(&mut OsRng, pk, &plaintext);

let coeff = Signed::random_bounded_bits(&mut OsRng, <PaillierTest as PaillierParams>::Uint::BITS as usize - 2);
let coeff = Signed::random_bounded_bits(&mut OsRng, <PaillierTest as PaillierParams>::Uint::BITS - 2);
let new_ciphertext = ciphertext * coeff;
let new_plaintext = new_ciphertext.decrypt(&sk);

Expand Down Expand Up @@ -498,8 +497,7 @@ mod tests {
let pk = sk.public_key();

let plaintext1 = <PaillierTest as PaillierParams>::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero());
let plaintext2 =
Signed::random_bounded_bits(&mut OsRng, <PaillierTest as PaillierParams>::Uint::BITS as usize - 2);
let plaintext2 = Signed::random_bounded_bits(&mut OsRng, <PaillierTest as PaillierParams>::Uint::BITS - 2);
let plaintext3 = <PaillierTest as PaillierParams>::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero());

let ciphertext1 = Ciphertext::<PaillierTest>::new(&mut OsRng, pk, &plaintext1);
Expand Down
4 changes: 2 additions & 2 deletions synedrion/src/paillier/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ where
(*modulus.modulus())
.inv_mod(primes.totient().expose_secret())
.expect("pq is invertible mod ϕ(pq) because gcd(pq, (p-1)(q-1)) = 1"),
P::MODULUS_BITS as u32,
P::MODULUS_BITS,
)
.expect("We assume `P::MODULUS_BITS` is properly configured")
})
Expand Down Expand Up @@ -224,7 +224,7 @@ where
.wrapping_shr_vartime(2)
.wrapping_add(&<P::HalfUint as Integer>::one())
});
let candidate = x.pow_bounded_exp(power.expose_secret(), P::PRIME_BITS as u32 - 1);
let candidate = x.pow_bounded_exp(power.expose_secret(), P::PRIME_BITS - 1);
if candidate.square() == *x {
Some(candidate)
} else {
Expand Down
6 changes: 3 additions & 3 deletions synedrion/src/paillier/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ use crate::{

pub trait PaillierParams: core::fmt::Debug + PartialEq + Eq + Clone + Send + Sync {
/// The size of one of the pair of RSA primes.
const PRIME_BITS: usize;
const PRIME_BITS: u32;
/// The size of the RSA modulus (a product of two primes).
const MODULUS_BITS: usize = Self::PRIME_BITS * 2;
const MODULUS_BITS: u32 = Self::PRIME_BITS * 2;
/// An integer that fits a single RSA prime.
type HalfUint: Integer<Monty = Self::HalfUintMod>
+ Bounded
Expand Down Expand Up @@ -103,7 +103,7 @@ pub(crate) struct PaillierTest;

#[cfg(test)]
impl PaillierParams for PaillierTest {
const PRIME_BITS: usize = 512;
const PRIME_BITS: u32 = 512;
type HalfUint = U512;
type HalfUintMod = U512Mod;
type Uint = U1024;
Expand Down
7 changes: 2 additions & 5 deletions synedrion/src/paillier/ring_pedersen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,8 @@ impl<P: PaillierParams> RPSecret<P> {
.expect("totient / 4 is still non-zero because p, q >= 5")
});
let lambda = SecretBox::init_with(|| {
Bounded::new(
P::Uint::random_mod(rng, bound.expose_secret()),
P::MODULUS_BITS as u32 - 2,
)
.expect("totient < N < 2^MODULUS_BITS, so totient / 4 < 2^(MODULUS_BITS - 2)")
Bounded::new(P::Uint::random_mod(rng, bound.expose_secret()), P::MODULUS_BITS - 2)
.expect("totient < N < 2^MODULUS_BITS, so totient / 4 < 2^(MODULUS_BITS - 2)")
})
.into();

Expand Down
16 changes: 8 additions & 8 deletions synedrion/src/paillier/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{

fn random_paillier_blum_prime<P: PaillierParams>(rng: &mut impl CryptoRngCore) -> P::HalfUint {
loop {
let prime = P::HalfUint::generate_prime_with_rng(rng, P::PRIME_BITS as u32);
let prime = P::HalfUint::generate_prime_with_rng(rng, P::PRIME_BITS);
if prime.as_ref()[0].0 & 3 == 3 {
return prime;
}
Expand Down Expand Up @@ -51,8 +51,8 @@ impl<P: PaillierParams> SecretPrimesWire<P> {
/// Creates a pair of safe primes.
pub fn random_safe(rng: &mut impl CryptoRngCore) -> Self {
Self::new(
SecretBox::init_with(|| P::HalfUint::generate_safe_prime_with_rng(rng, P::PRIME_BITS as u32)).into(),
SecretBox::init_with(|| P::HalfUint::generate_safe_prime_with_rng(rng, P::PRIME_BITS as u32)).into(),
SecretBox::init_with(|| P::HalfUint::generate_safe_prime_with_rng(rng, P::PRIME_BITS)).into(),
SecretBox::init_with(|| P::HalfUint::generate_safe_prime_with_rng(rng, P::PRIME_BITS)).into(),
)
}

Expand Down Expand Up @@ -141,13 +141,13 @@ impl<P: PaillierParams> SecretPrimes<P> {

pub fn p_signed(&self) -> SecretBox<Signed<P::Uint>> {
SecretBox::init_with(|| {
Signed::new_positive(*self.p().expose_secret(), P::PRIME_BITS as u32).expect("`P::PRIME_BITS` is valid")
Signed::new_positive(*self.p().expose_secret(), P::PRIME_BITS).expect("`P::PRIME_BITS` is valid")
})
}

pub fn q_signed(&self) -> SecretBox<Signed<P::Uint>> {
SecretBox::init_with(|| {
Signed::new_positive(*self.q().expose_secret(), P::PRIME_BITS as u32).expect("`P::PRIME_BITS` is valid")
Signed::new_positive(*self.q().expose_secret(), P::PRIME_BITS).expect("`P::PRIME_BITS` is valid")
})
}

Expand All @@ -169,7 +169,7 @@ impl<P: PaillierParams> SecretPrimes<P> {

pub fn totient_bounded(&self) -> SecretBox<Bounded<P::Uint>> {
SecretBox::init_with(|| {
Bounded::new(*self.totient.expose_secret(), P::MODULUS_BITS as u32).expect("`P::MODULUS_BITS` is valid")
Bounded::new(*self.totient.expose_secret(), P::MODULUS_BITS).expect("`P::MODULUS_BITS` is valid")
})
}

Expand All @@ -191,7 +191,7 @@ impl<P: PaillierParams> SecretPrimes<P> {
pub fn random_field_elem(&self, rng: &mut impl CryptoRngCore) -> Bounded<P::Uint> {
Bounded::new(
P::Uint::random_mod(rng, self.totient_nonzero().expose_secret()),
P::MODULUS_BITS as u32,
P::MODULUS_BITS,
)
.expect(concat![
"the totient is smaller than the modulus, ",
Expand Down Expand Up @@ -256,7 +256,7 @@ impl<P: PaillierParams> PublicModulus<P> {
}

pub fn modulus_bounded(&self) -> Bounded<P::Uint> {
Bounded::new(self.modulus.0, P::MODULUS_BITS as u32).expect("the modulus can be bounded by 2^MODULUS_BITS")
Bounded::new(self.modulus.0, P::MODULUS_BITS).expect("the modulus can be bounded by 2^MODULUS_BITS")
}

pub fn monty_params_mod_n(&self) -> &<P::UintMod as Monty>::Params {
Expand Down
5 changes: 0 additions & 5 deletions synedrion/src/uint/bounded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@ where
self.bound
}

pub fn bound_usize(&self) -> usize {
// Extracted into a method to localize the conversion
self.bound as usize
}

/// Creates a new [`Bounded`] wrapper around `T`, restricted to `bound`.
///
/// Returns `None` if the bound is invalid, i.e.:
Expand Down
37 changes: 15 additions & 22 deletions synedrion/src/uint/signed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,6 @@ where
self.bound
}

pub fn bound_usize(&self) -> usize {
// Extracted into a method to localize the conversion
self.bound as usize
}

/// Creates a signed value from an unsigned one,
/// assuming that it encodes a positive value.
pub fn new_positive(value: T, bound: u32) -> Option<Self> {
Expand Down Expand Up @@ -158,10 +153,10 @@ where

// Asserts that the value lies in the interval `[-2^bound, 2^bound]`.
// Panics if it is not the case.
pub fn assert_bound(self, bound: usize) {
pub fn assert_bound(self, bound: u32) {
assert!(
T::one()
.overflowing_shl_vartime(bound as u32)
.overflowing_shl_vartime(bound)
.map(|b| self.abs() <= b)
.expect("Out of bounds"),
"Out of bounds"
Expand Down Expand Up @@ -199,18 +194,18 @@ where
// Asserts that the value has bound less or equal to `bound`
// (or, in other words, the value lies in the interval `(-(2^bound-1), 2^bound-1)`).
// Returns the value with the bound set to `bound`.
pub fn assert_bit_bound_usize(self, bound: usize) -> Option<Self> {
if self.abs().bits_vartime() <= bound as u32 {
pub fn assert_bit_bound(self, bound: u32) -> Option<Self> {
if self.abs().bits_vartime() <= bound {
Some(Self {
value: self.value,
bound: bound as u32,
bound,
})
} else {
None
}
}
/// Returns `true` if the value is within `[-2^bound_bits, 2^bound_bits]`.
pub fn in_range_bits(&self, bound_bits: usize) -> bool {
pub fn in_range_bits(&self, bound_bits: u32) -> bool {
self.abs() <= T::one() << bound_bits
}

Expand Down Expand Up @@ -273,9 +268,9 @@ where
/// Returns a random value in range `[-2^bound_bits, 2^bound_bits]`.
///
/// Note: variable time in `bound_bits`.
pub fn random_bounded_bits(rng: &mut impl CryptoRngCore, bound_bits: usize) -> Self {
pub fn random_bounded_bits(rng: &mut impl CryptoRngCore, bound_bits: u32) -> Self {
assert!(
bound_bits < (T::BITS - 1) as usize,
bound_bits < T::BITS - 1,
"Out of bounds: bound_bits was {} but must be smaller than {}",
bound_bits,
T::BITS - 1
Expand Down Expand Up @@ -366,10 +361,9 @@ where
/// Note: variable time in `bound_bits` and bit size of `scale`.
pub fn random_bounded_bits_scaled(
rng: &mut impl CryptoRngCore,
bound_bits: usize,
bound_bits: u32,
scale: &Bounded<T>,
) -> Signed<T::Wide> {
let bound_bits = u32::try_from(bound_bits).expect("Assumed to fit in a u32; caller beware");
assert!(
bound_bits < T::BITS - 1,
"Out of bounds: bound_bits was {} but must be smaller than {}",
Expand Down Expand Up @@ -445,10 +439,9 @@ where
/// Note: variable time in `bound_bits` and `scale`.
pub fn random_bounded_bits_scaled_wide(
rng: &mut impl CryptoRngCore,
bound_bits: usize,
bound_bits: u32,
scale: &Bounded<T::Wide>,
) -> Signed<<T::Wide as HasWide>::Wide> {
let bound_bits = u32::try_from(bound_bits).expect("Assumed to fit in a u32; caller beware");
assert!(
bound_bits < T::BITS - 1,
"Out of bounds: bound_bits was {} but must be smaller than {}",
Expand Down Expand Up @@ -747,9 +740,9 @@ mod tests {
fn random_bounded_bits_is_sane() {
let mut rng = ChaCha8Rng::seed_from_u64(SEED);
for bound_bits in 1..U1024::BITS - 1 {
let signed: Signed<U1024> = Signed::random_bounded_bits(&mut rng, bound_bits as usize);
let signed: Signed<U1024> = Signed::random_bounded_bits(&mut rng, bound_bits);
assert!(signed.abs() < U1024::MAX >> (U1024::BITS - 1 - bound_bits));
signed.assert_bound(bound_bits as usize);
signed.assert_bound(bound_bits);
}
}

Expand All @@ -760,7 +753,7 @@ mod tests {
let value = U1024::from_u8(3);
let signed = Signed::new_from_unsigned(value, bound).unwrap();
assert!(signed.abs() < U1024::MAX >> (U1024::BITS - 1 - bound));
signed.assert_bound(bound as usize);
signed.assert_bound(bound);
// 4 is too big
let value = U1024::from_u8(4);
let signed = Signed::new_from_unsigned(value, bound);
Expand All @@ -771,7 +764,7 @@ mod tests {
let value = U1024::from_u8(1);
let signed = Signed::new_from_unsigned(value, bound).unwrap();
assert!(signed.abs() < U1024::MAX >> (U1024::BITS - 1 - bound));
signed.assert_bound(bound as usize);
signed.assert_bound(bound);
// 2 is too big
let value = U1024::from_u8(2);
let signed = Signed::new_from_unsigned(value, bound);
Expand All @@ -782,7 +775,7 @@ mod tests {
let value = U1024::from_u8(0);
let signed = Signed::new_from_unsigned(value, bound).unwrap();
assert!(signed.abs() < U1024::MAX >> (U1024::BITS - 1 - bound));
signed.assert_bound(bound as usize);
signed.assert_bound(bound);
// 1 is too big
let value = U1024::from_u8(1);
let signed = Signed::new_from_unsigned(value, bound);
Expand Down

0 comments on commit e3cbb41

Please sign in to comment.