use core::fmt;
use crate::int::Int;
use crate::mod_int::ModInt;
use crate::ring::Field;
fn field_mul_small<F: Field>(x: &F, mut n: u64) -> F {
let mut acc = x.zero();
let mut base = x.clone();
while n > 0 {
if n & 1 == 1 {
acc = acc + base.clone();
}
n >>= 1;
if n > 0 {
base = base.clone() + base.clone();
}
}
acc
}
#[derive(Clone)]
struct Jac<F: Field> {
x: F,
y: F,
z: F,
}
impl<F: Field> Jac<F> {
#[inline]
fn infinity(sample: &F) -> Jac<F> {
Jac {
x: sample.one(),
y: sample.one(),
z: sample.zero(),
}
}
#[inline]
fn is_infinity(&self) -> bool {
self.z.is_zero()
}
}
#[derive(Clone)]
pub struct EllipticCurve<F: Field> {
a: F,
b: F,
}
impl<F: Field> EllipticCurve<F> {
pub fn new(a: F, b: F) -> Option<EllipticCurve<F>> {
let curve = EllipticCurve { a, b };
if curve.discriminant().is_zero() {
None
} else {
Some(curve)
}
}
#[inline]
pub fn a(&self) -> &F {
&self.a
}
#[inline]
pub fn b(&self) -> &F {
&self.b
}
pub fn discriminant(&self) -> F {
let a3 = self.a.clone() * self.a.clone() * self.a.clone();
let b2 = self.b.clone() * self.b.clone();
let inner = field_mul_small(&a3, 4) + field_mul_small(&b2, 27);
-field_mul_small(&inner, 16)
}
pub fn j_invariant(&self) -> F {
let a3 = self.a.clone() * self.a.clone() * self.a.clone();
let b2 = self.b.clone() * self.b.clone();
let denom = field_mul_small(&a3, 4) + field_mul_small(&b2, 27);
field_mul_small(&a3, 6912) / denom
}
pub fn identity(&self) -> Point<F> {
Point {
curve: self.clone(),
coords: None,
}
}
fn rhs(&self, x: &F) -> F {
x.clone() * x.clone() * x.clone() + self.a.clone() * x.clone() + self.b.clone()
}
pub fn point(&self, x: F, y: F) -> Option<Point<F>> {
let p = Point {
curve: self.clone(),
coords: Some((x, y)),
};
if p.is_on_curve() { Some(p) } else { None }
}
fn jac_double(&self, p: &Jac<F>) -> Jac<F> {
if p.z.is_zero() || p.y.is_zero() {
return Jac::infinity(&self.a);
}
let xx = p.x.clone() * p.x.clone();
let yy = p.y.clone() * p.y.clone();
let yyyy = yy.clone() * yy.clone();
let zz = p.z.clone() * p.z.clone();
let z4 = zz.clone() * zz;
let s = field_mul_small(&(p.x.clone() * yy), 4);
let m = field_mul_small(&xx, 3) + self.a.clone() * z4;
let two_s = s.clone() + s.clone();
let x3 = m.clone() * m.clone() - two_s;
let y3 = m * (s - x3.clone()) - field_mul_small(&yyyy, 8);
let z3 = field_mul_small(&(p.y.clone() * p.z.clone()), 2);
Jac {
x: x3,
y: y3,
z: z3,
}
}
fn jac_add(&self, p1: &Jac<F>, p2: &Jac<F>) -> Jac<F> {
if p1.is_infinity() {
return p2.clone();
}
if p2.is_infinity() {
return p1.clone();
}
let z1z1 = p1.z.clone() * p1.z.clone();
let z2z2 = p2.z.clone() * p2.z.clone();
let u1 = p1.x.clone() * z2z2.clone();
let u2 = p2.x.clone() * z1z1.clone();
let s1 = p1.y.clone() * z2z2 * p2.z.clone();
let s2 = p2.y.clone() * z1z1 * p1.z.clone();
let h = u2 - u1.clone();
let r = s2 - s1.clone();
if h.is_zero() {
if r.is_zero() {
return self.jac_double(p1);
}
return Jac::infinity(&self.a);
}
let h2 = h.clone() * h.clone();
let h3 = h2.clone() * h.clone();
let u1h2 = u1 * h2;
let two_u1h2 = u1h2.clone() + u1h2.clone();
let x3 = r.clone() * r.clone() - h3.clone() - two_u1h2;
let y3 = r * (u1h2 - x3.clone()) - s1 * h3;
let z3 = p1.z.clone() * p2.z.clone() * h;
Jac {
x: x3,
y: y3,
z: z3,
}
}
fn jac_to_affine(&self, p: Jac<F>) -> Point<F> {
if p.is_infinity() {
return self.identity();
}
let z_inv = self.a.one() / p.z;
let z_inv2 = z_inv.clone() * z_inv.clone();
let z_inv3 = z_inv2.clone() * z_inv;
Point {
curve: self.clone(),
coords: Some((p.x * z_inv2, p.y * z_inv3)),
}
}
}
impl<F: Field + fmt::Display> fmt::Display for EllipticCurve<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "y² = x³ + {}·x + {}", self.a, self.b)
}
}
impl<F: Field + fmt::Debug> fmt::Debug for EllipticCurve<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "EllipticCurve {{ a: {:?}, b: {:?} }}", self.a, self.b)
}
}
impl<F: Field> PartialEq for EllipticCurve<F> {
fn eq(&self, other: &Self) -> bool {
self.a == other.a && self.b == other.b
}
}
#[derive(Clone)]
pub struct Point<F: Field> {
curve: EllipticCurve<F>,
coords: Option<(F, F)>,
}
impl<F: Field> Point<F> {
#[inline]
pub fn curve(&self) -> &EllipticCurve<F> {
&self.curve
}
#[inline]
pub fn is_infinity(&self) -> bool {
self.coords.is_none()
}
#[inline]
pub fn coordinates(&self) -> Option<(&F, &F)> {
self.coords.as_ref().map(|(x, y)| (x, y))
}
#[inline]
pub fn x(&self) -> Option<&F> {
self.coords.as_ref().map(|(x, _)| x)
}
#[inline]
pub fn y(&self) -> Option<&F> {
self.coords.as_ref().map(|(_, y)| y)
}
pub fn is_on_curve(&self) -> bool {
match &self.coords {
None => true,
Some((x, y)) => y.clone() * y.clone() == self.curve.rhs(x),
}
}
pub fn neg(&self) -> Point<F> {
match &self.coords {
None => self.clone(),
Some((x, y)) => Point {
curve: self.curve.clone(),
coords: Some((x.clone(), -y.clone())),
},
}
}
pub fn double(&self) -> Point<F> {
let (x, y) = match &self.coords {
None => return self.clone(),
Some(p) => p,
};
if y.is_zero() {
return self.curve.identity();
}
let three_x2 = field_mul_small(&(x.clone() * x.clone()), 3);
let num = three_x2 + self.curve.a.clone();
let den = y.clone() + y.clone();
let lambda = num / den;
self.line_result(&lambda, x, x, y)
}
pub fn add(&self, rhs: &Point<F>) -> Point<F> {
assert!(
self.curve == rhs.curve,
"Point::add: points lie on different curves"
);
let (x1, y1) = match &self.coords {
None => return rhs.clone(),
Some(p) => p,
};
let (x2, y2) = match &rhs.coords {
None => return self.clone(),
Some(p) => p,
};
if x1 == x2 {
if y1 == y2 {
return self.double();
}
return self.curve.identity();
}
let lambda = (y2.clone() - y1.clone()) / (x2.clone() - x1.clone());
self.line_result(&lambda, x1, x2, y1)
}
fn line_result(&self, lambda: &F, x1: &F, x2: &F, y1: &F) -> Point<F> {
let x3 = lambda.clone() * lambda.clone() - x1.clone() - x2.clone();
let y3 = lambda.clone() * (x1.clone() - x3.clone()) - y1.clone();
Point {
curve: self.curve.clone(),
coords: Some((x3, y3)),
}
}
pub fn scalar_mul(&self, k: &Int) -> Point<F> {
let (x, y) = match &self.coords {
_ if k.is_zero() => return self.curve.identity(),
None => return self.curve.identity(),
Some(p) => p,
};
let mag = k.abs();
let result = if F::CHEAP_INV {
let base = Point {
curve: self.curve.clone(),
coords: Some((x.clone(), y.clone())),
};
let mut acc = self.curve.identity();
let mut i = mag.bit_len();
while i > 0 {
i -= 1;
acc = acc.double();
if mag.bit(i) {
acc = acc.add(&base);
}
}
acc
} else {
let base = Jac {
x: x.clone(),
y: y.clone(),
z: x.one(),
};
let mut acc = Jac::infinity(&self.curve.a);
let mut i = mag.bit_len();
while i > 0 {
i -= 1;
acc = self.curve.jac_double(&acc);
if mag.bit(i) {
acc = self.curve.jac_add(&acc, &base);
}
}
self.curve.jac_to_affine(acc)
};
if k.is_negative() {
result.neg()
} else {
result
}
}
}
impl<F: Field> PartialEq for Point<F> {
fn eq(&self, other: &Self) -> bool {
self.curve == other.curve && self.coords == other.coords
}
}
impl<F: Field + fmt::Display> fmt::Display for Point<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.coords {
None => write!(f, "O"),
Some((x, y)) => write!(f, "({}, {})", x, y),
}
}
}
impl<F: Field + fmt::Debug> fmt::Debug for Point<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.coords {
None => write!(f, "Point(O)"),
Some((x, y)) => write!(f, "Point({:?}, {:?})", x, y),
}
}
}
impl<F: Field> core::ops::Add for Point<F> {
type Output = Point<F>;
#[inline]
fn add(self, rhs: Point<F>) -> Point<F> {
Point::add(&self, &rhs)
}
}
impl<F: Field> core::ops::Add<&Point<F>> for &Point<F> {
type Output = Point<F>;
#[inline]
fn add(self, rhs: &Point<F>) -> Point<F> {
Point::add(self, rhs)
}
}
impl<F: Field> core::ops::Neg for Point<F> {
type Output = Point<F>;
#[inline]
fn neg(self) -> Point<F> {
Point::neg(&self)
}
}
impl<F: Field> core::ops::Neg for &Point<F> {
type Output = Point<F>;
#[inline]
fn neg(self) -> Point<F> {
Point::neg(self)
}
}
impl EllipticCurve<ModInt> {
#[inline]
pub fn field_prime(&self) -> Int {
self.a.modulus()
}
pub fn point_from_x(&self, x: &ModInt) -> Option<Point<ModInt>> {
let p = self.field_prime();
let rhs = self.rhs(x);
let y = rhs.to_int().sqrt_mod(&p)?;
Some(Point {
curve: self.clone(),
coords: Some((x.clone(), x.of(y))),
})
}
pub fn curve_order(&self) -> Int {
let p = self.field_prime();
let mut count = Int::ONE;
let mut xi = self.a.of(Int::ZERO);
let one = self.a.of(Int::ONE);
let mut x = Int::ZERO;
while x < p {
let rhs = self.rhs(&xi);
if rhs.is_zero() {
count += Int::ONE; } else {
let leg = rhs.to_int().legendre(&p);
count += Int::from(1 + leg);
}
xi += one.clone();
x += Int::ONE;
}
count
}
pub fn order_of_point(&self, point: &Point<ModInt>) -> Int {
assert!(
*point.curve() == *self,
"order_of_point: point lies on a different curve"
);
if point.is_infinity() {
return Int::ONE;
}
let mut order = self.curve_order();
for q in order.clone().factorize() {
loop {
let (quot, rem) = order.div_rem_trunc(&q);
if !rem.is_zero() {
break;
}
if !point.scalar_mul(").is_infinity() {
break;
}
order = quot;
}
}
order
}
}