From: Matt Corallo Date: Tue, 7 May 2024 20:14:29 +0000 (+0000) Subject: Check the assumption that P-N is tiny X-Git-Tag: v0.5.4~4 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=fa27f6a0e6e778694bdd53b9168893918224096e;p=dnssec-prover Check the assumption that P-N is tiny --- diff --git a/src/crypto/ec.rs b/src/crypto/ec.rs index f116767..b16056c 100644 --- a/src/crypto/ec.rs +++ b/src/crypto/ec.rs @@ -85,6 +85,10 @@ pub(super) struct Point { } impl Point { + fn check_curve_conditions() { + debug_assert!(C::ScalarModulus::PRIME < C::CurveModulus::PRIME, "N is < P"); + } + fn on_curve(x: &C::CurveField, y: &C::CurveField) -> Result<(), ()> { let x_2 = x.square(); let x_3 = x_2.mul(&x); @@ -115,6 +119,8 @@ impl Point { } fn from_xy(x: C::Int, y: C::Int) -> Result { + Self::check_curve_conditions(); + let x = C::CurveField::from_i(x); let y = C::CurveField::from_i(y); Self::on_curve(&x, &y)?; @@ -127,12 +133,28 @@ impl Point { /// Checks that `expected_x` is equal to our X affine coordinate (without modular inversion). fn eq_x(&self, expected_x: &C::ScalarField) -> Result<(), ()> { - debug_assert!(expected_x.clone().into_i() < C::CurveModulus::PRIME, "N is < P"); - // If x is between N and P the below calculations will fail and we'll spuriously reject a // signature and the wycheproof tests will fail. We should in theory accept such // signatures, but the probability of this happening at random is roughly 1/2^128, i.e. we // really don't need to handle it in practice. Thus, we only bother to do this in tests. + debug_assert!(expected_x.clone().into_i() < C::CurveModulus::PRIME, "N is < P"); + debug_assert!(C::ScalarModulus::PRIME < C::CurveModulus::PRIME, "N is < P"); + #[cfg(debug_assertions)] { + // Check the above assertion - ensure the difference between the modulus of the scalar + // and curve fields is less than half the bit length of our integers, which are at + // least 256 bit long. + let scalar_mod_on_curve = C::CurveField::from_i(C::ScalarModulus::PRIME); + let diff = C::CurveField::ZERO.sub(&scalar_mod_on_curve); + assert!(C::Int::BYTES * 8 / 2 >= 128, "We assume 256-bit ints and longer"); + assert!(C::CurveModulus::PRIME.limbs()[0] > (1 << 63), "PRIME should have the top bit set"); + assert!(C::ScalarModulus::PRIME.limbs()[0] > (1 << 63), "PRIME should have the top bit set"); + let mut half_bitlen = C::CurveField::ONE; + for _ in 0..C::Int::BYTES * 8 / 2 { + half_bitlen = half_bitlen.double(); + } + assert!(diff.into_i() < half_bitlen.into_i()); + } + #[allow(unused_mut, unused_assignments)] let mut slow_check = None; #[cfg(test)] {