use crate::curve::{MontCurve, MontPoint};
use crate::fq::{Fq, PRIME};
use crate::isogeny;
pub const PRIMES: [u64; 74] = [
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 587,
];
pub const NUM_PRIMES: usize = 74;
pub const MAX_EXPONENT: i8 = 5;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Ideal {
pub exponents: [i8; NUM_PRIMES],
}
impl Ideal {
pub fn identity() -> Self {
Ideal {
exponents: [0; NUM_PRIMES],
}
}
pub fn from_exponents(e: &[i8]) -> Self {
let mut exponents = [0i8; NUM_PRIMES];
let len = if e.len() < NUM_PRIMES {
e.len()
} else {
NUM_PRIMES
};
let mut i = 0;
while i < len {
exponents[i] = e[i];
i += 1;
}
Ideal { exponents }
}
}
fn cofactor(ell: u64) -> [u64; 8] {
let mut qp1 = [0u64; 8];
let mut carry = 1u64;
let mut i = 0;
while i < 8 {
let (s, c) = PRIME[i].overflowing_add(carry);
qp1[i] = s;
carry = c as u64;
i += 1;
}
let mut result = [0u64; 8];
let mut rem = 0u128;
i = 8;
while i > 0 {
i -= 1;
rem = (rem << 64) | (qp1[i] as u128);
result[i] = (rem / (ell as u128)) as u64;
rem %= ell as u128;
}
result
}
struct XSampler {
counter: u64,
}
impl XSampler {
fn new() -> Self {
XSampler { counter: 0 }
}
fn next(&mut self) -> Fq {
let x = Fq::from_u64(self.counter);
self.counter += 1;
x
}
}
pub fn action(ideal: &Ideal, curve: &MontCurve) -> MontCurve {
let mut current = *curve;
let mut i = 0;
while i < NUM_PRIMES {
let mut e = ideal.exponents[i];
let ell = PRIMES[i];
while e != 0 {
let want_on_curve = e > 0;
let cof = cofactor(ell);
let mut sampler = XSampler::new();
loop {
let x = sampler.next();
let rhs = current.rhs(&x);
let leg = Fq::legendre(&rhs);
if leg == 0 {
continue; }
let on_curve = leg == 1;
if on_curve != want_on_curve {
continue;
}
let p = MontPoint::from_x(x);
let q_pt = p.ladder(&cof, ¤t.a);
if q_pt.is_inf() {
continue;
}
current = isogeny::isogeny_codomain(¤t, &q_pt, ell);
if e > 0 {
e -= 1;
} else {
e += 1;
}
break;
}
}
i += 1;
}
current
}
pub fn dh(secret: &Ideal, peer_curve: &MontCurve) -> MontCurve {
action(secret, peer_curve)
}