type FieldElementBuffer = [i64; 16];
#[derive(Clone,Debug,Default)]
pub struct FieldElement(FieldElementBuffer);
pub static D2: FieldElement = FieldElement([
0xf159, 0x26b2, 0x9b94, 0xebd6,
0xb156, 0x8283, 0x149a, 0x00e0,
0xd130, 0xeef3, 0x80f2, 0x198e,
0xfce7, 0x56df, 0xd9dc, 0x2406,
]);
pub static ZERO: FieldElement = FieldElement([
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
]);
pub static ONE: FieldElement = FieldElement([
1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
]);
pub static X: FieldElement = FieldElement([
0xd51a, 0x8f25, 0x2d60, 0xc956,
0xa7b2, 0x9525, 0xc760, 0x692c,
0xdc5c, 0xfdd6, 0xe231, 0xc0a4,
0x53fe, 0xcd6e, 0x36d3, 0x2169,
]);
pub static Y: FieldElement = FieldElement([
0x6658, 0x6666, 0x6666, 0x6666,
0x6666, 0x6666, 0x6666, 0x6666,
0x6666, 0x6666, 0x6666, 0x6666,
0x6666, 0x6666, 0x6666, 0x6666,
]);
use core::ops::Add;
impl<'a, 'b> Add<&'b FieldElement> for &'a FieldElement {
type Output = FieldElement;
fn add(self, other: &'b FieldElement) -> FieldElement {
let mut sum: FieldElementBuffer = Default::default();
for (s, (x, y)) in sum.iter_mut().zip(self.0.iter().zip(other.0.iter())) {
*s = x + y
}
FieldElement(sum)
}
}
use core::ops::Sub;
impl<'a, 'b> Sub<&'b FieldElement> for &'a FieldElement {
type Output = FieldElement;
fn sub(self, other: &'b FieldElement) -> FieldElement {
let mut sum: FieldElementBuffer = Default::default();
for (s, (x, y)) in sum.iter_mut().zip(self.0.iter().zip(other.0.iter())) {
*s = x - y
}
FieldElement(sum)
}
}
fn reduce(fe: &mut FieldElement) {
for i in 0..16 {
fe.0[i] += 1 << 16;
let carry = fe.0[i] >> 16;
fe.0[(i + 1) * ((i < 15) as usize)] +=
carry - 1 + 37 * (carry - 1) * ((i == 15) as i64);
fe.0[i] -= carry << 16;
}
}
use core::ops::Mul;
impl<'a, 'b> Mul<&'b FieldElement> for &'a FieldElement {
type Output = FieldElement;
fn mul(self, other: &'b FieldElement) -> FieldElement {
let mut pre_product: [i64; 31] = Default::default();
for i in 0..16 {
for j in 0..16 {
pre_product[i + j] += self.0[i] * other.0[j];
}
}
for i in 0..15 {
pre_product[i] += 38 * pre_product[i + 16];
}
let mut product: FieldElementBuffer = Default::default();
product.copy_from_slice(&mut pre_product[..16]);
let mut fe = FieldElement(product);
reduce(&mut fe);
reduce(&mut fe);
fe
}
}
impl<'a> Mul<&'a FieldElement> for FieldElement {
type Output = FieldElement;
fn mul(self, other: &'a FieldElement) -> Self::Output {
&self * other
}
}
impl<'a> Mul<FieldElement> for &'a FieldElement {
type Output = FieldElement;
fn mul(self, other: FieldElement) -> Self::Output {
self * &other
}
}
fn square(fe: &FieldElement) -> FieldElement {
fe * fe
}
pub fn invert(fe: &FieldElement) -> FieldElement {
let mut inverse = fe.clone();
for i in (0..=253).rev() {
inverse = square(&inverse); if i != 2 && i != 4 {
inverse = inverse * fe;
}
}
inverse
}
use core::ops::Div;
impl<'a, 'b> Div<&'b FieldElement> for &'a FieldElement {
type Output = FieldElement;
fn div(self, other: &'b FieldElement) -> FieldElement {
self * invert(other)
}
}
pub fn conditional_swap(p: &mut FieldElement, q: &mut FieldElement, b: i64) {
let mask: i64 = !(b - 1);
for (pi, qi) in p.0.iter_mut().zip(q.0.iter_mut()) {
let t = mask & (*pi ^ *qi);
*pi ^= t;
*qi ^= t;
}
}
pub fn from_le_bytes(bytes: &[u8; 32]) -> FieldElement {
let mut limbs: FieldElementBuffer = Default::default();
for i in 0..16 {
limbs[i] = (bytes[2 * i] as i64) + (bytes[2 * i + 1] as i64) << 8;
}
limbs[15] &= 0x7fff;
FieldElement(limbs)
}
pub fn freeze_to_le_bytes(fe: &FieldElement) -> [u8; 32] {
let mut fe = fe.clone();
reduce(&mut fe);
reduce(&mut fe);
reduce(&mut fe);
let mut m: FieldElementBuffer = Default::default();
for _j in 0..2 {
m[0] = fe.0[0] - 0xffed;
for i in 1..15 {
m[i] = fe.0[i] - 0xffff - ((m[i - 1] >> 16) & 1);
m[i - 1] &= 0xffff;
}
m[15] = fe.0[15] - 0x7fff - ((m[14] >> 16) & 1);
let b = (m[15] >> 16) & 1;
m[14] &= 0xffff;
conditional_swap(&mut fe, &mut FieldElement(m), 1 - b);
}
let mut bytes: [u8; 32] = Default::default();
for i in 0..16 {
bytes[2 * i] = fe.0[i] as u8; bytes[2 * i + 1] = (fe.0[i] >> 8) as u8;
}
bytes
}
pub fn parity(a: &FieldElement) -> u8 {
let d = freeze_to_le_bytes(a);
d[0] & 1
}