use super::gf2m257::FieldElement;
fn b() -> FieldElement {
FieldElement::from_be_bytes(&[
0x01, 0xCE, 0xF4, 0x94, 0x72, 0x01, 0x15, 0x65, 0x7E, 0x18, 0xF9, 0x38, 0xD7, 0xA7, 0x94,
0x23, 0x94, 0xFF, 0x94, 0x25, 0xC1, 0x45, 0x8C, 0x57, 0x86, 0x1F, 0x9E, 0xEA, 0x6A, 0xDB,
0xE3, 0xBE, 0x10,
])
}
fn gx() -> FieldElement {
FieldElement::from_be_bytes(&[
0x00, 0x2A, 0x29, 0xEF, 0x20, 0x7D, 0x0E, 0x9B, 0x6C, 0x55, 0xCD, 0x26, 0x0B, 0x30, 0x6C,
0x7E, 0x00, 0x7A, 0xC4, 0x91, 0xCA, 0x1B, 0x10, 0xC6, 0x23, 0x34, 0xA9, 0xE8, 0xDC, 0xD8,
0xD2, 0x0F, 0xB7,
])
}
fn gy() -> FieldElement {
FieldElement::from_be_bytes(&[
0x01, 0x06, 0x86, 0xD4, 0x1F, 0xF7, 0x44, 0xD4, 0x44, 0x9F, 0xCC, 0xF6, 0xD8, 0xEE, 0xA0,
0x31, 0x02, 0xE6, 0x81, 0x2C, 0x93, 0xA9, 0xD6, 0x0B, 0x97, 0x8B, 0x70, 0x2C, 0xF1, 0x56,
0xD8, 0x14, 0xEF,
])
}
#[must_use]
pub fn order() -> [u8; 33] {
[
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x67, 0x59, 0x21, 0x3A, 0xF1, 0x82, 0xE9, 0x87, 0xD3, 0xE1, 0x77, 0x14, 0x90,
0x7D, 0x47, 0x0D,
]
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Point {
Infinity,
Affine(FieldElement, FieldElement),
}
impl Point {
#[must_use]
pub fn generator() -> Self {
Point::Affine(gx(), gy())
}
#[must_use]
pub fn negate(self) -> Self {
match self {
Point::Infinity => Point::Infinity,
Point::Affine(x, y) => Point::Affine(x, x + y),
}
}
#[must_use]
pub fn is_on_curve(self) -> bool {
match self {
Point::Infinity => false,
Point::Affine(x, y) => {
let lhs = y.square() + x.multiply(y);
let rhs = x.multiply(x.square()) + b();
lhs == rhs
}
}
}
#[must_use]
pub fn double(self) -> Self {
match self {
Point::Infinity => Point::Infinity,
Point::Affine(x1, y1) => {
if x1 == FieldElement::ZERO {
return Point::Infinity;
}
let lambda = x1 + y1.multiply(x1.invert());
let x3 = lambda.square() + lambda;
let y3 = x1.square() + (lambda + FieldElement::ONE).multiply(x3);
Point::Affine(x3, y3)
}
}
}
#[must_use]
pub fn scalar_multiply(self, k: &[u8; 33]) -> Self {
match self {
Point::Infinity => Point::Infinity,
Point::Affine(x, y) => {
let mut x1 = FieldElement::ONE;
let mut z1 = FieldElement::ZERO; let mut x2 = x;
let mut z2 = FieldElement::ONE;
for i in (0..257u32).rev() {
let bit = bit_at(k, i);
let swap = bit ^ 1;
cswap(swap, &mut x1, &mut x2);
cswap(swap, &mut z1, &mut z2);
let t1 = z1;
z1 = (x1.multiply(z2) + x2.multiply(z1)).square();
x1 = x.multiply(z1) + x1.multiply(x2).multiply(t1).multiply(z2);
let t2 = x2;
x2 = x2.square().square() + b().multiply(z2.square().square());
z2 = t2.square().multiply(z2.square());
cswap(swap, &mut x1, &mut x2);
cswap(swap, &mut z1, &mut z2);
}
if is_zero_mask(z1) != 0 {
return Point::Infinity;
}
let x1_affine = x1.multiply(z1.invert());
let x2_affine = x2.multiply(z2.invert());
let t1 = x1_affine + x;
let t2 = x2_affine + x;
let inner = t1.multiply(t2) + x.square() + y;
let y1_affine_formula = x.invert().multiply(t1).multiply(inner) + y;
let y1_affine = select(is_zero_mask(z2), x + y, y1_affine_formula);
Point::Affine(x1_affine, y1_affine)
}
}
}
}
impl core::ops::Add for Point {
type Output = Self;
fn add(self, other: Self) -> Self {
match (self, other) {
(Point::Infinity, q) => q,
(p, Point::Infinity) => p,
(Point::Affine(x1, y1), Point::Affine(x2, y2)) => {
if x1 == x2 {
if y1 == y2 {
return self.double();
}
return Point::Infinity;
}
let lambda = (y1 + y2).multiply((x1 + x2).invert());
let x3 = lambda.square() + lambda + x1 + x2;
let y3 = lambda.multiply(x1 + x3) + x3 + y1;
Point::Affine(x3, y3)
}
}
}
}
fn bit_at(bytes: &[u8; 33], i: u32) -> u64 {
let byte_index = 32 - (i / 8) as usize;
let bit_in_byte = i % 8;
u64::from((bytes[byte_index] >> bit_in_byte) & 1)
}
fn cswap(swap: u64, a: &mut FieldElement, b: &mut FieldElement) {
let mask = 0u64.wrapping_sub(swap);
for i in 0..5 {
let t = mask & (a.0[i] ^ b.0[i]);
a.0[i] ^= t;
b.0[i] ^= t;
}
}
fn is_zero_mask(a: FieldElement) -> u64 {
let combined = a.0[0] | a.0[1] | a.0[2] | a.0[3] | a.0[4];
let is_nonzero = (combined | combined.wrapping_neg()) >> 63;
0u64.wrapping_sub(1 ^ is_nonzero)
}
fn select(mask: u64, if_mask: FieldElement, otherwise: FieldElement) -> FieldElement {
let mut out = [0u64; 5];
for ((out_limb, a), b) in out.iter_mut().zip(if_mask.0.iter()).zip(otherwise.0.iter()) {
*out_limb = b ^ (mask & (a ^ b));
}
FieldElement(out)
}