use crate::models::twisted_edwards::*;
use crate::prelude::*;
#[cfg(feature = "curve25519")]
use crate::curves::curve25519::Curve25519Point;
elliptic_curve! {
[attributes]
name = Ed25519
model = TwistedEdwards
field_size = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed
group_size = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
generator = (0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A,
0x6666666666666666666666666666666666666666666666666666666666666658,
0x1,
0x67875f0fd78b766566ea4e8e64abe37d20f09f80775152f56dde8ab3a5b7dda3)
identity = (0x0, 0x1, 0x1, 0x0)
[constants]
a = -1
d = 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3
[properties]
serialized_bytes = 33
}
impl Ed25519Point {
pub fn serialize(self) -> [u8; 32] {
let mut result = [0u8; 32];
let long = <Self as SerializePoint>::serialize(self);
result.copy_from_slice(&long[0..32]);
result[31] |= (long[32] & 0x01) << 7;
result
}
pub fn deserialize(bytes: &[u8; 32]) -> Self {
let mut long = [0u8; 33];
long[0..32].copy_from_slice(&bytes[0..32]);
long[32] = (bytes[31] >> 7) & 0x01;
long[31] &= 0x7F;
<Self as DeserializePoint>::deserialize(*GenericArray::from_slice(&long))
}
#[cfg(feature = "curve25519")]
pub fn to_montgomery(&self) -> Curve25519Point {
let u = TwistedEdwardsModel::montgomery_u(*self);
<Curve25519Point as DeserializePoint>::deserialize(u.serialize())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn identity_generator() {
let g = <Ed25519 as EllipticCurve>::Point::generator();
let res = g.clone().add(<Ed25519 as EllipticCurve>::Point::identity());
let a = res.clone().serialize();
let b = <Ed25519 as EllipticCurve>::Point::generator().serialize();
assert!(bool::from(g.equal(res)), "Identity + generator error: expected {:?}, but received {:?}", a, b);
}
#[test]
fn decompress_basepoint() {
let bytes = [
0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
];
let p = Ed25519Point::deserialize(&bytes);
let g = <Ed25519 as EllipticCurve>::Point::generator();
assert!(
bool::from(p.clone().equal(g.clone())),
"Decompress basepoint error: expected \n{:#?}, but received \n{:#?}",
g,
p
);
let serialized = g.serialize();
assert!(
bytes == serialized,
"Compress basepoint error: expected {:?}, but received {:?}",
bytes,
serialized
);
}
#[test]
fn serialize_deserialize() {
let g = <Ed25519 as EllipticCurve>::Point::generator();
for _ in 0..32 {
let s = <Ed25519 as EllipticCurve>::Scalar::random(rand::rng());
let r0 = g.clone().scalar_mul(s);
let r1 = Ed25519Point::deserialize(&r0.clone().serialize());
assert!(r0.clone().equal(r1.clone()).unwrap_u8() != 0, "Expected \n{:#?}, but received \n{:#?}", r0, r1)
}
}
#[test]
fn small_multiplication() {
let g = <Ed25519 as EllipticCurve>::Point::generator();
let mut p0 = g.clone();
for i in 1usize..32usize {
let s = <Ed25519 as EllipticCurve>::Scalar::from_usize(i);
let p1 = g.clone().scalar_mul(s);
let r0 = p0.clone().serialize();
let r1 = p1.clone().serialize();
assert!(
bool::from(p0.clone().equal(p1)),
"Small Randomized Multiplication {} error: expected {:?}, but received {:?}",
i,
&r0,
&r1
);
p0 = p0.clone().add(g.clone());
}
}
#[test]
fn multiplication() {
let g = <Ed25519 as EllipticCurve>::Point::generator();
for i in 1..32 {
let s0 = <Ed25519 as EllipticCurve>::Scalar::random(rand::rng());
let s1 = <Ed25519 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, &r1, &r2);
}
}
#[test]
fn test_negation() {
let g = <Ed25519 as EllipticCurve>::Point::generator();
for _ in 1..32 {
let s = <Ed25519 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<<Ed25519 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<<Ed25519 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 basepoint_edwards_to_montgomery() {
let mont = Ed25519Point::generator().to_montgomery();
assert!(
bool::from(mont.equal(Curve25519Point::generator())),
"Edwards generator does not map to Montgomery generator, got {mont:#?} instead",
);
}
}