From ce1d3effc283d22fe33ee327a422af4fd18d02fa Mon Sep 17 00:00:00 2001 From: Vincent Hanquez Date: Fri, 13 Sep 2024 09:53:37 +0800 Subject: [PATCH] more stuff --- src/constant_time.rs | 26 +++++++++ src/curve25519/fe/fe64/mod.rs | 27 ++++++---- src/curve25519/fe/mod.rs | 59 ++++++++++----------- src/curve25519/ge.rs | 99 ++++++++++++++++++++++++++++++----- src/ed25519.rs | 6 ++- 5 files changed, 161 insertions(+), 56 deletions(-) diff --git a/src/constant_time.rs b/src/constant_time.rs index 945e7c3..f804f56 100644 --- a/src/constant_time.rs +++ b/src/constant_time.rs @@ -430,4 +430,30 @@ mod tests { let a: [u8; 4] = [0u8, 1, 2, 3]; assert_eq!(<&[u8; 4]>::ct_lt(&a, &[1, 1, 2, 3]).is_true(), true); } + + #[test] + fn test_maybe_swap() { + let c = Choice(0); + const VAL1: [u64; 2] = [0x12, 0x34]; + const VAL2: [u64; 2] = [0x80, 0x90]; + let mut a = VAL1; + let mut b = VAL2; + ct_array64_maybe_swap_with(&mut a, &mut b, c); + assert_eq!(a, VAL1); + assert_eq!(b, VAL2); + ct_array64_maybe_swap_with(&mut a, &mut b, c.negate()); + assert_eq!(a, VAL2); + assert_eq!(b, VAL1); + } + + #[test] + fn test_maybe_set() { + let c = Choice(0); + let mut a = [0x12, 0x34]; + let b = [0x80, 0x90]; + ct_array64_maybe_set(&mut a, &b, c); + assert_eq!(a, [0x12, 0x34]); + ct_array64_maybe_set(&mut a, &b, c.negate()); + assert_eq!(a, [0x80, 0x90]); + } } diff --git a/src/curve25519/fe/fe64/mod.rs b/src/curve25519/fe/fe64/mod.rs index 697bef2..927d6f9 100644 --- a/src/curve25519/fe/fe64/mod.rs +++ b/src/curve25519/fe/fe64/mod.rs @@ -15,7 +15,7 @@ const FOUR_P0: u64 = 0x1fffffffffffb4; const FOUR_P1234: u64 = 0x1ffffffffffffc; /// Field Element in ℤ/(2^255-19) -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct Fe(pub(crate) [u64; 5]); impl CtEqual for &Fe { @@ -53,11 +53,11 @@ impl Fe { /// Field element constant for -1. pub(crate) const M1: Fe = Fe([ - 2251799813685228, - 2251799813685247, - 2251799813685247, - 2251799813685247, - 2251799813685247, + 0x7FFFFFFFFFFEC, + 0x7FFFFFFFFFFFF, + 0x7FFFFFFFFFFFF, + 0x7FFFFFFFFFFFF, + 0x7FFFFFFFFFFFF, ]); /// Field element constant for D @@ -83,11 +83,11 @@ impl Fe { /// Field element for Montgomery curve value -486662 pub(crate) const MONTGOMERY_A_NEG: Fe = Fe([ - 2251799813198567, - 2251799813685247, - 2251799813685247, - 2251799813685247, - 2251799813685247, + 0x7FFFFFFF892E7, + 0x7FFFFFFFFFFFF, + 0x7FFFFFFFFFFFF, + 0x7FFFFFFFFFFFF, + 0x7FFFFFFFFFFFF, ]); } @@ -415,6 +415,11 @@ impl Fe { CtEqual::ct_ne(&self.to_bytes(), &[0; 32]).into() } + /// Check that the field element is 'negative' + pub fn is_negative_u8(&self) -> u8 { + (self.to_packed()[0] & 1) as u8 + } + /// Check that the field element is 'negative' pub fn is_negative_ct(&self) -> Choice { (self.to_packed()[0] & 1).ct_ne(0) diff --git a/src/curve25519/fe/mod.rs b/src/curve25519/fe/mod.rs index 1ac07f2..0d64bce 100644 --- a/src/curve25519/fe/mod.rs +++ b/src/curve25519/fe/mod.rs @@ -29,33 +29,10 @@ use crate::constant_time::{Choice, CtEqual}; impl Fe { /// Raise a field element to (p-5) / 8 = 2^252-3 pub fn pow_252_3(&self) -> Fe { - let z1 = self; - let z2 = z1.square(); - let z8 = z2.square_repeatdly(2); - let z9 = z1 * &z8; - let z11 = &z2 * &z9; - let z22 = z11.square(); - let z_5_0 = &z9 * &z22; - let z_10_5 = z_5_0.square_repeatdly(5); - let z_10_0 = &z_10_5 * &z_5_0; - let z_20_10 = z_10_0.square_repeatdly(10); - let z_20_0 = &z_20_10 * &z_10_0; - let z_40_20 = z_20_0.square_repeatdly(20); - let z_40_0 = &z_40_20 * &z_20_0; - let z_50_10 = z_40_0.square_repeatdly(10); - let z_50_0 = &z_50_10 * &z_10_0; - let z_100_50 = z_50_0.square_repeatdly(50); - let z_100_0 = &z_100_50 * &z_50_0; - let z_200_100 = z_100_0.square_repeatdly(100); - let z_200_0 = &z_200_100 * &z_100_0; - let z_250_50 = z_200_0.square_repeatdly(50); - let z_250_0 = &z_250_50 * &z_50_0; - let z_250_2 = z_250_0.square_repeatdly(2); - let z_252_0 = &z_250_2 * &z1; - z_252_0 + self.pow25523() } - /// Raise a field element to 2^255-23 + /// Raise a field element to (p-5)/8 = (2^255-19-5)/2^3 = 2^252-3 pub fn pow25523(&self) -> Fe { let z2 = self.square(); let z8 = z2.square_repeatdly(2); @@ -83,7 +60,7 @@ impl Fe { z_252_3 } - /// Calculate the invert of the Field element + /// Calculate the inverse of the Field element /// /// the element to invert must be non 0 pub fn invert(&self) -> Fe { @@ -114,27 +91,45 @@ impl Fe { z_255_21 } - pub(crate) fn sqrt_ratio_i(u: &Self, v: &Self) -> (Choice, Fe) { + pub(crate) fn sqrt_check(u: &Self, v: &Self) -> (Choice, Fe) { let v3 = &v.square() * &v; let v7 = &v3.square() * &v; let mut r = &(u * &v3) * &(u * &v7).pow_252_3(); let check = v * &r.square(); - let i = &Fe::SQRTM1; + let correct_sign_sqrt = check.ct_eq(u); + let flipped_sign_sqrt = check.ct_eq(&(-u)); + let flipped_sign_sqrt_i = check.ct_eq(&(&(-u) * &Fe::SQRTM1)); + + let r_prime = &Fe::SQRTM1 * &r; + Fe::maybe_set(&mut r, &r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i); + + let was_nonzero_square = correct_sign_sqrt | flipped_sign_sqrt; + + (was_nonzero_square, r) + } + + pub(crate) fn sqrt_ratio_i(u: &Self, v: &Self) -> (Choice, Fe) { + let v3 = &v.square() * &v; + let v7 = &v3.square() * &v; + let mut r = &(u * &v3) * &(u * &v7).pow_252_3(); + let check = v * &r.square(); let correct_sign_sqrt = check.ct_eq(u); let flipped_sign_sqrt = check.ct_eq(&(-u)); - let flipped_sign_sqrt_i = check.ct_eq(&(&(-u) * i)); + let flipped_sign_sqrt_i = check.ct_eq(&(&(-u) * &Fe::SQRTM1)); let r_prime = &Fe::SQRTM1 * &r; Fe::maybe_set(&mut r, &r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i); // Choose the nonnegative square root. let r_is_negative = r.is_negative_ct(); - let mut r_neg = r.clone(); - r_neg.negate_mut(); + let mut r_negated = r.clone(); + r_negated.negate_mut(); + + Fe::maybe_set(&mut r, &r_negated, r_is_negative); - Fe::maybe_set(&mut r, &r_neg, r_is_negative); + assert!(!r.is_negative()); let was_nonzero_square = correct_sign_sqrt | flipped_sign_sqrt; diff --git a/src/curve25519/ge.rs b/src/curve25519/ge.rs index cc06cc6..a05d8e5 100644 --- a/src/curve25519/ge.rs +++ b/src/curve25519/ge.rs @@ -15,7 +15,7 @@ use crate::constant_time::{Choice, CtEqual, CtZero}; /// X = x/z /// Y = y/z /// X * Y = t/z -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct Ge { x: Fe, y: Fe, @@ -85,25 +85,32 @@ impl GeAffine { let u = &y2 - &Fe::ONE; let v = &(&y2 * &Fe::D) + &Fe::ONE; - let (is_valid_y_coord, mut x) = Fe::sqrt_ratio_i(&u, &v); + //let (is_valid_y_coord, mut x) = Fe::sqrt_ratio_i(&u, &v); + let (is_valid_y_coord, mut x) = Fe::sqrt_check(&u, &v); if is_valid_y_coord.is_false() { return None; } - let sign_bit = x_0.ct_eq(1); + let use_negated = x_0.ct_eq(1) ^ x.is_negative_ct(); - let mut x_neg = x.clone(); - x_neg.negate_mut(); + let mut x_negated = x.clone(); + x_negated.negate_mut(); - x.maybe_set(&x_neg, sign_bit); + x.maybe_set(&x_negated, use_negated.negate()); let Self { x: x2, y: y2 } = Self::from_bytes2(s).unwrap(); - //assert_eq!(y.to_bytes(), y2.to_bytes(), "y mismatch"); - //assert_eq!(x.to_bytes(), x2.to_bytes(), "x mismatch"); + assert_eq!(y.to_bytes(), y2.to_bytes(), "y mismatch"); + assert_eq!( + x.to_bytes(), + x2.to_bytes(), + "x mismatch {:?}", + x_negated.to_bytes() + ); - Some(Self { x: x2, y: y2 }) + //Some(Self { x: x2, y: y2 }) + Some(Self { x, y }) } pub fn from_bytes2(s: &[u8; 32]) -> Option { @@ -454,7 +461,7 @@ impl MontgomeryPoint { let mut y_bytes = y.to_bytes(); println!("y_bytes[31] {:b}", &y_bytes[31]); - y_bytes[31] ^= sign << 7; + y_bytes[31] ^= (if sign == 0 { 1 } else { 0 }) << 7; println!("y_bytes[31] {:b}", &y_bytes[31]); println!("y_bytes {:x?}", &y_bytes); @@ -650,8 +657,76 @@ impl GePrecomp { #[cfg(test)] mod tests { - use super::Ge; - use crate::hashing::sha512; + use super::{Ge, MontgomeryPoint}; + use crate::{curve25519::Fe, hashing::sha512}; + + pub const X25519_BASEPOINT: MontgomeryPoint = MontgomeryPoint([ + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ]); + + pub const ED25519_BASEPOINT_POINT: Ge = Ge { + x: Fe([ + 1738742601995546, + 1146398526822698, + 2070867633025821, + 562264141797630, + 587772402128613, + ]), + y: Fe([ + 1801439850948184, + 1351079888211148, + 450359962737049, + 900719925474099, + 1801439850948198, + ]), + z: Fe([1, 0, 0, 0, 0]), + t: Fe([ + 1841354044333475, + 16398895984059, + 755974180946558, + 900171276175154, + 1821297809914039, + ]), + }; + + pub const ED25519_BASEPOINT_POINT_NEG: Ge = Ge { + x: Fe([ + 513057211689683, + 1105401286862549, + 180932180659426, + 1689535671887617, + 1664027411556634, + ]), + y: Fe([ + 1801439850948184, + 1351079888211148, + 450359962737049, + 900719925474099, + 1801439850948198, + ]), + z: Fe::ONE, + t: Fe([ + 410445769351754, + 2235400917701188, + 1495825632738689, + 1351628537510093, + 430502003771208, + ]), + }; + + #[test] + fn basepoint_montgomery_to_edwards() { + assert_eq!( + ED25519_BASEPOINT_POINT, + X25519_BASEPOINT.to_edwards(0).unwrap() + ); + assert_eq!( + ED25519_BASEPOINT_POINT_NEG, + X25519_BASEPOINT.to_edwards(1).unwrap() + ); + } #[test] fn elligator() { diff --git a/src/ed25519.rs b/src/ed25519.rs index e021c7b..0be1308 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -226,8 +226,12 @@ pub fn verify( let r = GePartial::double_scalarmult_vartime(&a_scalar, a, &signature_scalar); let rcheck = r.to_bytes(); + if &rcheck != signature_left { + println!("{:x?} == {:x?}", rcheck, signature_left) + } - CtEqual::ct_eq(&rcheck, signature_left).into() + &rcheck == signature_left + // CtEqual::ct_eq(&rcheck, signature_left).into() } /// Curve25519 DH (Diffie Hellman) between a curve25519 public key and a ED25519 keypair key