use crate::models::montgomery::*;
use crate::prelude::*;
#[cfg(feature = "ed25519")]
use crate::curves::ed25519::Ed25519Point;
#[cfg(feature = "ed25519")]
use subtle::ConditionallySelectable;
elliptic_curve! {
[attributes]
name = Curve25519
model = Montgomery
field_size = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed
group_size = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
generator = (0x09, 0x1)
identity = (0x1, 0x0)
[constants]
a = 0x76d06
b = 0x01
[properties]
serialized_bytes = 32
}
impl Curve25519Point {
#[cfg(feature = "ed25519")]
pub fn to_edwards(&self, sign: subtle::Choice) -> Ed25519Point {
let y_pos = Ed25519Point::deserialize(&MontgomeryModel::edwards_y(*self).serialize().into_array());
let y_neg = y_pos.neg();
Ed25519Point::conditional_select(&y_pos, &y_neg, sign)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialize_deserialize_generator() {
let g = <Curve25519 as EllipticCurve>::Point::generator();
let r1 = <<Curve25519 as EllipticCurve>::Point as DeserializePoint>::deserialize(g.serialize());
assert!(g.equal(r1.clone()).unwrap_u8() != 0, "Expected \n{:#?}, but received \n{:#?}", g, r1)
}
#[test]
fn serialize_deserialize() {
let g = <Curve25519 as EllipticCurve>::Point::generator();
let s = <Curve25519 as EllipticCurve>::Scalar::random(rand::rng());
let r0 = g.scalar_mul(s);
let r1 = <<Curve25519 as EllipticCurve>::Point as DeserializePoint>::deserialize(r0.serialize());
assert!(r0.clone().equal(r1.clone()).unwrap_u8() != 0, "Expected \n{:#?}, but received \n{:#?}", r0, r1)
}
#[test]
fn small_multiplication() {
let g = <Curve25519 as EllipticCurve>::Point::generator();
let mut p0 = g.clone();
let mut s = DynamicElement::ONE;
for i in 0usize..32usize {
let p1 = g.clone().scalar_mul(s);
let r0 = p0.clone().serialize();
let r1 = p1.serialize();
assert!(
r0 == r1,
"Small Randomized Multiplication s=2^{} error: expected {:?}, but received {:?}",
i,
&r0,
&r1
);
s = s.dbl();
p0 = p0.dbl();
}
}
#[test]
fn multiplication() {
let g = <Curve25519 as EllipticCurve>::Point::generator();
for i in 1..32 {
let s0 = <Curve25519 as EllipticCurve>::Scalar::random(rand::rng());
let s1 = <Curve25519 as EllipticCurve>::Scalar::random(rand::rng());
let s2 = s0 * s1;
let p0 = g.clone().scalar_mul(s0);
let p1 = p0.clone().scalar_mul(s1);
let p2 = g.clone().scalar_mul(s2);
let r1 = p1.serialize();
let r2 = p2.serialize();
assert!(r1 == r2, "Randomized Multiplication {} error: expected {:#?}, but received {:#?}", i, &p1, &p2);
}
}
#[test]
fn test_negation() {
let g = <Curve25519 as EllipticCurve>::Point::generator();
for _ in 1..32 {
let s = <Curve25519 as EllipticCurve>::Scalar::random(rand::rng());
let p = g.clone().scalar_mul(s);
assert!(bool::from(p.clone().neg().neg().equal(p)), "Could not double negate on {s:?}");
}
}
#[test]
fn test_one_minus_one() {
let one: DynamicElement<<Curve25519 as EllipticCurve>::Scalar> = DynamicElement::ONE;
let minus_one = -one;
let zero = DynamicElement::ZERO;
assert_eq!(zero, one + minus_one);
assert_eq!(zero, one - one);
assert_eq!(zero, one + -one);
let one: DynamicElement<<Curve25519 as EllipticCurve>::Base> = DynamicElement::ONE;
let minus_one = -one;
let zero = DynamicElement::ZERO;
assert_eq!(zero, one + minus_one);
assert_eq!(zero, one - one);
assert_eq!(zero, one + -one);
}
#[test]
fn via_edwards() {
let g = <Curve25519 as EllipticCurve>::Point::generator();
let roundtrip = g.to_edwards(subtle::Choice::from(0u8)).to_montgomery();
assert!(bool::from(g.equal(roundtrip)), "Roundtrip via Edwards failed");
}
#[test]
fn basepoint_montgomery_to_edwards() {
let ed = Curve25519Point::generator().to_edwards(0.into());
assert!(
bool::from(ed.equal(Ed25519Point::generator())),
"Montgomery generator does not map to Edwards generator, got {:#?} instead",
ed
);
let ed = Curve25519Point::generator().to_edwards(1.into());
assert!(
bool::from(ed.equal(Ed25519Point::generator().neg())),
"Montgomery generator does not map to Edwards generator, got {ed:#?} instead",
);
}
}