more tests, working better

This commit is contained in:
Neemek 2025-10-09 15:29:51 +02:00
parent 14cfa2efb0
commit eebad9991a
Signed by: neemek
GPG key ID: 84FFE4D7D40AB25E
2 changed files with 163 additions and 35 deletions

View file

@ -1,11 +1,8 @@
use std::fmt::{Display, Formatter, Write};
use crypto_bigint::{Encoding, MulMod, NonZero, Odd, Random, U256};
use crypto_bigint::{ConstChoice, Encoding, MulMod, NonZero, Odd, Random, U256};
use std::ops::Mul;
use crypto_bigint::rand_core::OsRng;
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
/// By^2 = x^3 + Ax^2 + x
#[derive(Clone, Copy, Debug)]
@ -57,19 +54,19 @@ impl MontgomeryPoint {
pub fn add(&self, rhs: MontgomeryPoint, neg: MontgomeryPoint) -> MontgomeryPoint {
let p = &NonZero::new(CURVE_25519.p).unwrap();
let mut v_0 = self.x + self.z; // 1: V_0 = X_P + Z_P
let mut v_1 = rhs.x.wrapping_sub(&rhs.z); // 2: V_1 = X_Q - Z_Q
let mut v_0 = self.x.add_mod(&self.z, p); // 1: V_0 = X_P + Z_P
let mut v_1 = rhs.x.sub_mod(&rhs.z, p); // 2: V_1 = X_Q - Z_Q
v_1 = v_1.mul_mod(&v_0, p); // 3: V_1 = V_1 * V_0
v_0 = self.x.sub_mod(&self.z, p); // 4: V_0 = X_P - Z_P
let mut v_2 = rhs.x.add_mod(&rhs.z, p); // 5: V_2 = X_Q + Z_Q
v_2 = v_2.mul_mod(&v_0, p); // 6: V_2 = V_2 * V_0
let mut v_3 = v_1 + v_2; // 7: V_3 = V_1 + V_2
let mut v_3 = v_1.add_mod(&v_2, p); // 7: V_3 = V_1 + V_2
v_3 = v_3.mul_mod(&v_3, p); // 8: V_3 = V_3^2
let mut v_4 = v_1.sub_mod(&v_2, p); // 9: V_4 = V_1 - V_2
v_4 = v_4.mul_mod(&v_4, p); // 10:
v_4 = v_4.mul_mod(&v_4, p); // 10: v_4 = v_4^2
let x = neg.z.mul_mod(&v_3, p); // 11: X_⨁ = Z_⊝ * V_3
let z = neg.x.mul_mod(&v_4, p); // 12: Z_⨁ = X_⊝ * V_4
@ -107,8 +104,10 @@ impl MontgomeryPoint {
}
pub fn get_x(&self) -> U256 {
let inv = self.z.inv_odd_mod(&Odd::new(CURVE_25519.p).unwrap());
self.x.mul_mod(&inv.unwrap(), &NonZero::new(self.curve.p).unwrap())
self.x.mul_mod(
&self.z.inv_mod(&CURVE_25519.p).unwrap(),
&NonZero::new(self.curve.p).unwrap()
)
}
}
@ -121,13 +120,13 @@ impl Display for MontgomeryPoint {
impl Mul<U256> for MontgomeryPoint {
type Output = MontgomeryPoint;
/// ~constant-time~ montgomery ladder
/// (not)constant-time montgomery ladder
fn mul(self, rhs: U256) -> Self::Output {
let mut x_0 = self;
let mut x_1 = x_0.double();
for i in (0..rhs.bits() - 2).rev() {
if rhs.bit(i).into() {
for i in (0..rhs.bits() - 1).rev() {
if rhs.bit(i).eq(&ConstChoice::FALSE) {
x_0 = x_0.double();
x_1 = x_0.add(x_1, self);
} else {
@ -185,15 +184,15 @@ pub const CURVE_25519: MontgomeryCurve = MontgomeryCurve::new(
);
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Public(U256);
impl From<&Secret> for Public {
fn from(s: &Secret) -> Public {
let p = CURVE_25519.point(U256::from_u8(9));
let x = (p * clamp_u256(s.0)).get_x();
let x_k = (p * s.0).get_x();
Public(x)
Public(x_k)
}
}
@ -206,13 +205,14 @@ impl Secret {
}
pub fn diffie_hellman(&self, public: Public) -> Secret {
let b = public.0; // public
let a = self.0; // private
let p = public.0; // public
let s = self.0; // secret
println!("p: {}\ns: {}", p, s);
let p = CURVE_25519.point(b);
let s = p * a;
let point = CURVE_25519.point(p);
let p = point * s;
Secret(s.get_x())
Secret(p.get_x())
}
}
@ -232,6 +232,26 @@ impl From<U256> for Secret {
mod tests {
use super::*;
#[test]
fn public_key_derivation() {
let a = Secret(U256::from_u8(3));
let p = Public::from(&a);
let x_k = U256::from_be_hex("1c12bc1a6d57abe645534d91c21bba64f8824e67621c0859c00a03affb713c12");
assert_eq!(p.0, x_k);
}
#[test]
fn shared_key_derivation() {
let s = Secret(U256::from_u8(2));
let p = Public(U256::from_u8(3));
let x = s.diffie_hellman(p);
let x_k = U256::from_be_hex("0933dc6ed7122bdf2a5f1b0516e218b743868769778787cfa1ac0ae2dfa89891");
assert_eq!(x.0, x_k);
}
#[test]
fn diffie_hellman() {
let a = Secret::random();
@ -247,4 +267,117 @@ mod tests {
assert_eq!(sa, sb);
}
#[test]
fn direct_diffie_hellman() {
let o = CURVE_25519.point(U256::from_u8(9));
// multiples of 8
let a = U256::from_u8(2 << 3);
let b = U256::from_u8(3 << 3);
let pa = (o * a).get_x();
let pb = (o * b).get_x();
let pap = CURVE_25519.point(pa);
let sa = (pap * b).get_x();
let pbp = CURVE_25519.point(pb);
let sb = (pbp * a).get_x();
assert_eq!(sa, sb);
}
#[test]
fn montgomery_point_double() {
let p = &NonZero::new(CURVE_25519.p).unwrap();
let point = CURVE_25519.point(U256::from_u8(2));
let dbl = point.double();
let x_k = U256::from_be_hex("3c0c7855eae09525fb741a3649b05a2da70d0e6b0ff35660a3feba622566fc9c");
assert_eq!(dbl.get_x(), x_k);
}
#[test]
fn montgomery_point_get_x() {
let point = MontgomeryPoint{
x: U256::from_u8(2),
z: U256::from_u8(3),
curve: CURVE_25519,
};
let k_x = U256::from_be_hex("2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa5");
assert_eq!(point.get_x(), k_x);
}
#[test]
fn montgomery_point_add() {
let p = &NonZero::new(CURVE_25519.p).unwrap();
let point_p = CURVE_25519.point(U256::from_u8(2));
let point_q = point_p.double();
let sum = point_p.add(point_q, point_p);
let x_k = U256::from_be_hex("56f0b3e7e53fed658bf39e9f8691055ba8a58a935482b00b21b5678c16261fec");
assert_eq!(sum.get_x(), x_k);
}
#[test]
fn montgomery_ladder_double() {
let p = MontgomeryPoint{
x: U256::from_u8(2),
z: U256::from_u8(3),
curve: CURVE_25519,
};
let n = U256::from_u8(2);
let a = p * n;
let b = p.double();
assert_eq!(a.get_x(), b.get_x());
}
#[test]
fn montgomery_ladder() {
let p = CURVE_25519.point(U256::from_u8(2));
let n = U256::from_u8(3);
let a = p * n;
let x_k = U256::from_be_hex("56f0b3e7e53fed658bf39e9f8691055ba8a58a935482b00b21b5678c16261fec");
assert_eq!(a.get_x(), x_k);
}
#[test]
fn montgomery_ladder_commutative() {
let p = CURVE_25519.point(U256::from_u8(2));
let n_1 = U256::from_u8(3);
let n_2 = U256::from_u8(4);
let a = p * n_1 * n_2;
let b = p * n_2 * n_1;
assert_eq!(a.get_x(), b.get_x());
}
#[test]
fn montgomery_point_conversion() {
let p = CURVE_25519.point(U256::from_u8(9));
let n_1 = U256::from_u8(3);
let n_2 = U256::from_u8(4);
let a = p * n_1;
let x_a = a.get_x();
let pa = CURVE_25519.point(x_a) * n_2;
assert_eq!(pa.get_x(), (a * n_2).get_x());
}
}

View file

@ -1,19 +1,14 @@
use crypto_bigint::rand_core::OsRng;
use crypto_bigint::U256;
use crypto_bigint::Random;
use diffie_hellman::{Public, Secret, CURVE_25519};
use diffie_hellman::{Public, Secret};
fn main() {
println!("{}", CURVE_25519.p);
let a = Secret::random();
let b = Secret::random();
let A = Public::from(&a);
let B = Public::from(&b);
let pa = Public::from(&a);
let pb = Public::from(&b);
let sa = a.diffie_hellman(B);
let sb = b.diffie_hellman(A);
let sa = a.diffie_hellman(pb);
let sb = b.diffie_hellman(pa);
println!("{} == {}", sa, sb)
}