use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use core::convert::TryFrom;
use super::{addcarry_u64, subborrow_u64, umull, umull_x2, umull_x2_add, sgnw, lzcnt};
#[derive(Clone, Copy, Debug)]
pub struct GFsecp256k1([u64; 4]);
impl GFsecp256k1 {
const T256_MINUS_Q: u64 = 0x1000003D1;
const MOD0: u64 = 0xFFFFFFFEFFFFFC2F;
pub const MODULUS: [u64; 4] = [
Self::MOD0,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF
];
pub const ENC_LEN: usize = 32;
pub const ZERO: GFsecp256k1 = GFsecp256k1([ 0, 0, 0, 0 ]);
pub const ONE: GFsecp256k1 = GFsecp256k1([ 1, 0, 0, 0 ]);
pub const MINUS_ONE: GFsecp256k1 = GFsecp256k1([
Self::MOD0 - 1,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
]);
pub const fn w64le(x0: u64, x1: u64, x2: u64, x3: u64) -> Self {
Self([ x0, x1, x2, x3 ])
}
pub const fn w64be(x3: u64, x2: u64, x1: u64, x0: u64) -> Self {
Self([ x0, x1, x2, x3 ])
}
pub fn from_w64le(x0: u64, x1: u64, x2: u64, x3: u64) -> Self {
Self([ x0, x1, x2, x3 ])
}
pub fn from_w64be(x3: u64, x2: u64, x1: u64, x0: u64) -> Self {
Self([ x0, x1, x2, x3 ])
}
const INVT510: GFsecp256k1 = GFsecp256k1::w64be(
0xD708F5127DC51882, 0x581B84F43014A31E,
0xD90854CCA9FCEEE6, 0xB246C2F829C913E4);
#[inline(always)]
pub fn from_i32(x: i32) -> Self {
Self::from_w64le(
Self::MOD0.wrapping_add((x as i64) as u64),
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF)
}
#[inline(always)]
pub fn from_u32(x: u32) -> Self {
Self::from_w64le(x as u64, 0, 0, 0)
}
#[inline(always)]
pub fn from_i64(x: i64) -> Self {
let x0 = x as u64;
let xh = (x >> 63) as u64;
let (d0, cc) = addcarry_u64(x0, Self::MOD0, 0);
let (d1, cc) = addcarry_u64(xh, 0xFFFFFFFFFFFFFFFF, cc);
let (d2, cc) = addcarry_u64(xh, 0xFFFFFFFFFFFFFFFF, cc);
let (d3, cc) = addcarry_u64(xh, 0xFFFFFFFFFFFFFFFF, cc);
let w = (cc as u64).wrapping_neg() & !xh;
let (d0, cc) = addcarry_u64(d0, Self::T256_MINUS_Q & w, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, _) = addcarry_u64(d3, 0, cc);
Self([ d0, d1, d2, d3 ])
}
#[inline(always)]
pub fn from_u64(x: u64) -> Self {
Self::from_w64le(x, 0, 0, 0)
}
#[inline(always)]
pub fn from_i128(x: i128) -> Self {
let x0 = x as u64;
let x1 = (x >> 64) as u64;
let xh = (x >> 127) as u64;
let (d0, cc) = addcarry_u64(x0, Self::MOD0, 0);
let (d1, cc) = addcarry_u64(x1, 0xFFFFFFFFFFFFFFFF, cc);
let (d2, cc) = addcarry_u64(xh, 0xFFFFFFFFFFFFFFFF, cc);
let (d3, cc) = addcarry_u64(xh, 0xFFFFFFFFFFFFFFFF, cc);
let w = (cc as u64).wrapping_neg() & !xh;
let (d0, cc) = addcarry_u64(d0, Self::T256_MINUS_Q & w, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, _) = addcarry_u64(d3, 0, cc);
Self([ d0, d1, d2, d3 ])
}
#[inline(always)]
pub fn from_u128(x: u128) -> Self {
Self::from_w64le(x as u64, (x >> 64) as u64, 0, 0)
}
#[inline]
fn set_add(&mut self, rhs: &Self) {
let (d0, cc) = addcarry_u64(self.0[0], rhs.0[0], 0);
let (d1, cc) = addcarry_u64(self.0[1], rhs.0[1], cc);
let (d2, cc) = addcarry_u64(self.0[2], rhs.0[2], cc);
let (d3, cc) = addcarry_u64(self.0[3], rhs.0[3], cc);
let (d0, cc) = addcarry_u64(d0,
(cc as u64).wrapping_neg() & Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, cc) = addcarry_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let d0 = d0.wrapping_add(w & Self::T256_MINUS_Q);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline]
fn set_sub(&mut self, rhs: &Self) {
let (d0, cc) = subborrow_u64(self.0[0], rhs.0[0], 0);
let (d1, cc) = subborrow_u64(self.0[1], rhs.0[1], cc);
let (d2, cc) = subborrow_u64(self.0[2], rhs.0[2], cc);
let (d3, cc) = subborrow_u64(self.0[3], rhs.0[3], cc);
let (d0, cc) = subborrow_u64(d0,
(cc as u64).wrapping_neg() & Self::T256_MINUS_Q, 0);
let (d1, cc) = subborrow_u64(d1, 0, cc);
let (d2, cc) = subborrow_u64(d2, 0, cc);
let (d3, cc) = subborrow_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let d0 = d0.wrapping_sub(w & Self::T256_MINUS_Q);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline]
pub fn set_neg(&mut self) {
let (d0, cc) = subborrow_u64(Self::MOD0, self.0[0], 0);
let (d1, cc) = subborrow_u64(0xFFFFFFFFFFFFFFFF, self.0[1], cc);
let (d2, cc) = subborrow_u64(0xFFFFFFFFFFFFFFFF, self.0[2], cc);
let (d3, cc) = subborrow_u64(0xFFFFFFFFFFFFFFFF, self.0[3], cc);
let e = (cc as u64).wrapping_neg();
let (d0, cc) = subborrow_u64(d0, e & Self::T256_MINUS_Q, 0);
let (d1, cc) = subborrow_u64(d1, 0, cc);
let (d2, cc) = subborrow_u64(d2, 0, cc);
let (d3, _) = subborrow_u64(d3, 0, cc);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline]
pub fn set_cond(&mut self, a: &Self, ctl: u32) {
let cw = ((ctl as i32) as i64) as u64;
self.0[0] ^= cw & (self.0[0] ^ a.0[0]);
self.0[1] ^= cw & (self.0[1] ^ a.0[1]);
self.0[2] ^= cw & (self.0[2] ^ a.0[2]);
self.0[3] ^= cw & (self.0[3] ^ a.0[3]);
}
#[inline(always)]
pub fn select(a0: &Self, a1: &Self, ctl: u32) -> Self {
let mut r = *a0;
r.set_cond(a1, ctl);
r
}
#[inline]
pub fn cswap(a: &mut Self, b: &mut Self, ctl: u32) {
let cw = ((ctl as i32) as i64) as u64;
let t = cw & (a.0[0] ^ b.0[0]); a.0[0] ^= t; b.0[0] ^= t;
let t = cw & (a.0[1] ^ b.0[1]); a.0[1] ^= t; b.0[1] ^= t;
let t = cw & (a.0[2] ^ b.0[2]); a.0[2] ^= t; b.0[2] ^= t;
let t = cw & (a.0[3] ^ b.0[3]); a.0[3] ^= t; b.0[3] ^= t;
}
#[inline]
fn set_half(&mut self) {
let d0 = (self.0[0] >> 1) | (self.0[1] << 63);
let d1 = (self.0[1] >> 1) | (self.0[2] << 63);
let d2 = (self.0[2] >> 1) | (self.0[3] << 63);
let d3 = self.0[3] >> 1;
let tt = (self.0[0] & 1).wrapping_neg();
let (d0, cc) = addcarry_u64(d0,
tt & ((((Self::MOD0 + 1) as i64) >> 1) as u64), 0);
let (d1, cc) = addcarry_u64(d1, tt, cc);
let (d2, cc) = addcarry_u64(d2, tt, cc);
let (d3, _) = addcarry_u64(d3, tt >> 1, cc);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline(always)]
pub fn half(self) -> Self {
let mut r = self;
r.set_half();
r
}
#[inline]
pub fn set_mul2(&mut self) {
let tt = ((self.0[3] as i64) >> 63) as u64;
let d0 = self.0[0] << 1;
let d1 = (self.0[0] >> 63) | (self.0[1] << 1);
let d2 = (self.0[1] >> 63) | (self.0[2] << 1);
let d3 = (self.0[2] >> 63) | (self.0[3] << 1);
let (d0, cc) = addcarry_u64(d0, tt & Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, cc) = addcarry_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let (d0, _) = addcarry_u64(d0, w & Self::T256_MINUS_Q, 0);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline(always)]
pub fn mul2(self) -> Self {
let mut r = self;
r.set_mul2();
r
}
#[inline]
pub fn set_mul4(&mut self) {
let tt = self.0[3] >> 62;
let d0 = self.0[0] << 2;
let d1 = (self.0[0] >> 62) | (self.0[1] << 2);
let d2 = (self.0[1] >> 62) | (self.0[2] << 2);
let d3 = (self.0[2] >> 62) | (self.0[3] << 2);
let (d0, cc) = addcarry_u64(d0, tt * Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, cc) = addcarry_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let (d0, _) = addcarry_u64(d0, w & Self::T256_MINUS_Q, 0);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline(always)]
pub fn mul4(self) -> Self {
let mut r = self;
r.set_mul4();
r
}
#[inline]
pub fn set_mul8(&mut self) {
let tt = self.0[3] >> 61;
let d0 = self.0[0] << 3;
let d1 = (self.0[0] >> 61) | (self.0[1] << 3);
let d2 = (self.0[1] >> 61) | (self.0[2] << 3);
let d3 = (self.0[2] >> 61) | (self.0[3] << 3);
let (d0, cc) = addcarry_u64(d0, tt * Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, cc) = addcarry_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let (d0, _) = addcarry_u64(d0, w & Self::T256_MINUS_Q, 0);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline(always)]
pub fn mul8(self) -> Self {
let mut r = self;
r.set_mul8();
r
}
#[inline]
pub fn set_mul16(&mut self) {
let tt = self.0[3] >> 60;
let d0 = self.0[0] << 4;
let d1 = (self.0[0] >> 60) | (self.0[1] << 4);
let d2 = (self.0[1] >> 60) | (self.0[2] << 4);
let d3 = (self.0[2] >> 60) | (self.0[3] << 4);
let (d0, cc) = addcarry_u64(d0, tt * Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, cc) = addcarry_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let (d0, _) = addcarry_u64(d0, w & Self::T256_MINUS_Q, 0);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline(always)]
pub fn mul16(self) -> Self {
let mut r = self;
r.set_mul16();
r
}
#[inline]
pub fn set_mul32(&mut self) {
let tt = self.0[3] >> 59;
let d0 = self.0[0] << 5;
let d1 = (self.0[0] >> 59) | (self.0[1] << 5);
let d2 = (self.0[1] >> 59) | (self.0[2] << 5);
let d3 = (self.0[2] >> 59) | (self.0[3] << 5);
let (d0, cc) = addcarry_u64(d0, tt * Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, cc) = addcarry_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let (d0, _) = addcarry_u64(d0, w & Self::T256_MINUS_Q, 0);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline(always)]
pub fn mul32(self) -> Self {
let mut r = self;
r.set_mul32();
r
}
#[inline]
pub fn set_mul_u16(&mut self, x: u16) {
let b = x as u64;
let (d0, d1) = umull(self.0[0], b);
let (d2, d3) = umull(self.0[2], b);
let (lo, hi) = umull(self.0[1], b);
let (d1, cc) = addcarry_u64(d1, lo, 0);
let (d2, cc) = addcarry_u64(d2, hi, cc);
let (lo, d4) = umull(self.0[3], b);
let (d3, cc) = addcarry_u64(d3, lo, cc);
let (d4, _) = addcarry_u64(d4, 0, cc);
let (d0, cc) = addcarry_u64(d0, d4 * Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, cc) = addcarry_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let (d0, _) = addcarry_u64(d0, w & Self::T256_MINUS_Q, 0);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline(always)]
pub fn mul_u16(self, x: u16) -> Self {
let mut r = self;
r.set_mul_u16(x);
r
}
#[inline(always)]
pub fn set_mul3(&mut self) {
self.set_mul_u16(3);
}
#[inline(always)]
pub fn mul3(self) -> Self {
let mut r = self;
r.set_mul3();
r
}
#[inline(always)]
pub fn set_mul21(&mut self) {
self.set_mul_u16(21);
}
#[inline(always)]
pub fn mul21(self) -> Self {
let mut r = self;
r.set_mul21();
r
}
#[inline(always)]
fn set_mul(&mut self, rhs: &Self) {
let (a0, a1, a2, a3) = (self.0[0], self.0[1], self.0[2], self.0[3]);
let (b0, b1, b2, b3) = (rhs.0[0], rhs.0[1], rhs.0[2], rhs.0[3]);
let (e0, e1) = umull(a0, b0);
let (e2, e3) = umull(a1, b1);
let (e4, e5) = umull(a2, b2);
let (e6, e7) = umull(a3, b3);
let (lo, hi) = umull(a0, b1);
let (e1, cc) = addcarry_u64(e1, lo, 0);
let (e2, cc) = addcarry_u64(e2, hi, cc);
let (lo, hi) = umull(a0, b3);
let (e3, cc) = addcarry_u64(e3, lo, cc);
let (e4, cc) = addcarry_u64(e4, hi, cc);
let (lo, hi) = umull(a2, b3);
let (e5, cc) = addcarry_u64(e5, lo, cc);
let (e6, cc) = addcarry_u64(e6, hi, cc);
let (e7, _) = addcarry_u64(e7, 0, cc);
let (lo, hi) = umull(a1, b0);
let (e1, cc) = addcarry_u64(e1, lo, 0);
let (e2, cc) = addcarry_u64(e2, hi, cc);
let (lo, hi) = umull(a3, b0);
let (e3, cc) = addcarry_u64(e3, lo, cc);
let (e4, cc) = addcarry_u64(e4, hi, cc);
let (lo, hi) = umull(a3, b2);
let (e5, cc) = addcarry_u64(e5, lo, cc);
let (e6, cc) = addcarry_u64(e6, hi, cc);
let (e7, _) = addcarry_u64(e7, 0, cc);
let (lo, hi) = umull(a0, b2);
let (e2, cc) = addcarry_u64(e2, lo, 0);
let (e3, cc) = addcarry_u64(e3, hi, cc);
let (lo, hi) = umull(a1, b3);
let (e4, cc) = addcarry_u64(e4, lo, cc);
let (e5, cc) = addcarry_u64(e5, hi, cc);
let (e6, cc) = addcarry_u64(e6, 0, cc);
let (e7, _) = addcarry_u64(e7, 0, cc);
let (lo, hi) = umull(a2, b0);
let (e2, cc) = addcarry_u64(e2, lo, 0);
let (e3, cc) = addcarry_u64(e3, hi, cc);
let (lo, hi) = umull(a3, b1);
let (e4, cc) = addcarry_u64(e4, lo, cc);
let (e5, cc) = addcarry_u64(e5, hi, cc);
let (e6, cc) = addcarry_u64(e6, 0, cc);
let (e7, _) = addcarry_u64(e7, 0, cc);
let (lo, hi) = umull(a1, b2);
let (lo2, hi2) = umull(a2, b1);
let (lo, cc) = addcarry_u64(lo, lo2, 0);
let (hi, tt) = addcarry_u64(hi, hi2, cc);
let (e3, cc) = addcarry_u64(e3, lo, 0);
let (e4, cc) = addcarry_u64(e4, hi, cc);
let (e5, cc) = addcarry_u64(e5, tt as u64, cc);
let (e6, cc) = addcarry_u64(e6, 0, cc);
let (e7, _) = addcarry_u64(e7, 0, cc);
let (lo, h0) = umull(e4, Self::T256_MINUS_Q);
let (e0, cc) = addcarry_u64(e0, lo, 0);
let (lo, h1) = umull(e5, Self::T256_MINUS_Q);
let (e1, cc) = addcarry_u64(e1, lo, cc);
let (lo, h2) = umull(e6, Self::T256_MINUS_Q);
let (e2, cc) = addcarry_u64(e2, lo, cc);
let (lo, h3) = umull(e7, Self::T256_MINUS_Q);
let (e3, cc) = addcarry_u64(e3, lo, cc);
let (h3, _) = addcarry_u64(h3, 0, cc);
let (lo, hi) = umull(h3, Self::T256_MINUS_Q);
let (e0, cc) = addcarry_u64(e0, lo, 0);
let (e1, cc) = addcarry_u64(e1, h0 + hi, cc);
let (e2, cc) = addcarry_u64(e2, h1, cc);
let (e3, cc) = addcarry_u64(e3, h2, cc);
let w = (cc as u64).wrapping_neg();
let (e0, cc) = addcarry_u64(e0, w & Self::T256_MINUS_Q, 0);
let (e1, cc) = addcarry_u64(e1, 0, cc);
let (e2, cc) = addcarry_u64(e2, 0, cc);
let (e3, _) = addcarry_u64(e3, 0, cc);
self.0[0] = e0;
self.0[1] = e1;
self.0[2] = e2;
self.0[3] = e3;
}
#[inline(always)]
pub fn set_square(&mut self) {
let (a0, a1, a2, a3) = (self.0[0], self.0[1], self.0[2], self.0[3]);
let (e1, e2) = umull(a0, a1);
let (e3, e4) = umull(a0, a3);
let (e5, e6) = umull(a2, a3);
let (lo, hi) = umull(a0, a2);
let (e2, cc) = addcarry_u64(e2, lo, 0);
let (e3, cc) = addcarry_u64(e3, hi, cc);
let (lo, hi) = umull(a1, a3);
let (e4, cc) = addcarry_u64(e4, lo, cc);
let (e5, cc) = addcarry_u64(e5, hi, cc);
let (e6, _) = addcarry_u64(e6, 0, cc);
let (lo, hi) = umull(a1, a2);
let (e3, cc) = addcarry_u64(e3, lo, 0);
let (e4, cc) = addcarry_u64(e4, hi, cc);
let (e5, cc) = addcarry_u64(e5, 0, cc);
let (e6, _) = addcarry_u64(e6, 0, cc);
let e7 = e6 >> 63;
let e6 = (e6 << 1) | (e5 >> 63);
let e5 = (e5 << 1) | (e4 >> 63);
let e4 = (e4 << 1) | (e3 >> 63);
let e3 = (e3 << 1) | (e2 >> 63);
let e2 = (e2 << 1) | (e1 >> 63);
let e1 = e1 << 1;
let (e0, hi) = umull(a0, a0);
let (e1, cc) = addcarry_u64(e1, hi, 0);
let (lo, hi) = umull(a1, a1);
let (e2, cc) = addcarry_u64(e2, lo, cc);
let (e3, cc) = addcarry_u64(e3, hi, cc);
let (lo, hi) = umull(a2, a2);
let (e4, cc) = addcarry_u64(e4, lo, cc);
let (e5, cc) = addcarry_u64(e5, hi, cc);
let (lo, hi) = umull(a3, a3);
let (e6, cc) = addcarry_u64(e6, lo, cc);
let (e7, _) = addcarry_u64(e7, hi, cc);
let (lo, h0) = umull(e4, Self::T256_MINUS_Q);
let (e0, cc) = addcarry_u64(e0, lo, 0);
let (lo, h1) = umull(e5, Self::T256_MINUS_Q);
let (e1, cc) = addcarry_u64(e1, lo, cc);
let (lo, h2) = umull(e6, Self::T256_MINUS_Q);
let (e2, cc) = addcarry_u64(e2, lo, cc);
let (lo, h3) = umull(e7, Self::T256_MINUS_Q);
let (e3, cc) = addcarry_u64(e3, lo, cc);
let (h3, _) = addcarry_u64(h3, 0, cc);
let (lo, hi) = umull(h3, Self::T256_MINUS_Q);
let (e0, cc) = addcarry_u64(e0, lo, 0);
let (e1, cc) = addcarry_u64(e1, h0 + hi, cc);
let (e2, cc) = addcarry_u64(e2, h1, cc);
let (e3, cc) = addcarry_u64(e3, h2, cc);
let w = (cc as u64).wrapping_neg();
let (e0, cc) = addcarry_u64(e0, w & Self::T256_MINUS_Q, 0);
let (e1, cc) = addcarry_u64(e1, 0, cc);
let (e2, cc) = addcarry_u64(e2, 0, cc);
let (e3, _) = addcarry_u64(e3, 0, cc);
self.0[0] = e0;
self.0[1] = e1;
self.0[2] = e2;
self.0[3] = e3;
}
#[inline(always)]
pub fn square(self) -> Self {
let mut r = self;
r.set_square();
r
}
#[inline(always)]
fn set_xsquare(&mut self, n: u32) {
for _ in 0..n {
self.set_square();
}
}
#[inline(always)]
pub fn xsquare(self, n: u32) -> Self {
let mut r = self;
r.set_xsquare(n);
r
}
#[inline]
fn set_normalized(&mut self) {
let (_, cc) = addcarry_u64(self.0[0], Self::T256_MINUS_Q, 0);
let (_, cc) = addcarry_u64(self.0[1], 0, cc);
let (_, cc) = addcarry_u64(self.0[2], 0, cc);
let (_, cc) = addcarry_u64(self.0[3], 0, cc);
let w = (cc as u64).wrapping_neg();
let (d0, cc) = addcarry_u64(self.0[0], w & Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(self.0[1], 0, cc);
let (d2, cc) = addcarry_u64(self.0[2], 0, cc);
let (d3, _) = addcarry_u64(self.0[3], 0, cc);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline]
fn set_lin(&mut self, u: &Self, v: &Self, f: u64, g: u64) {
let sf = sgnw(f);
let f = (f ^ sf).wrapping_sub(sf);
let tu = Self::select(u, &-u, sf as u32);
let sg = sgnw(g);
let g = (g ^ sg).wrapping_sub(sg);
let tv = Self::select(v, &-v, sg as u32);
let (d0, t) = umull_x2(tu.0[0], f, tv.0[0], g);
let (d1, t) = umull_x2_add(tu.0[1], f, tv.0[1], g, t);
let (d2, t) = umull_x2_add(tu.0[2], f, tv.0[2], g, t);
let (d3, t) = umull_x2_add(tu.0[3], f, tv.0[3], g, t);
let (lo, hi) = umull(t, Self::T256_MINUS_Q);
let (d0, cc) = addcarry_u64(d0, lo, 0);
let (d1, cc) = addcarry_u64(d1, hi, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, cc) = addcarry_u64(d3, 0, cc);
let w = (cc as u64).wrapping_neg();
let (d0, cc) = addcarry_u64(d0, w & Self::T256_MINUS_Q, 0);
let (d1, _) = addcarry_u64(d1, 0, cc);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
}
#[inline(always)]
fn lin(a: &Self, b: &Self, f: u64, g: u64) -> Self {
let mut r = Self::ZERO;
r.set_lin(a, b, f, g);
r
}
#[inline]
fn set_lindiv31abs(&mut self, a: &Self, b: &Self, f: u64, g: u64) -> u64 {
let sf = sgnw(f);
let f = (f ^ sf).wrapping_sub(sf);
let sg = sgnw(g);
let g = (g ^ sg).wrapping_sub(sg);
let (a0, cc) = subborrow_u64(a.0[0] ^ sf, sf, 0);
let (a1, cc) = subborrow_u64(a.0[1] ^ sf, sf, cc);
let (a2, cc) = subborrow_u64(a.0[2] ^ sf, sf, cc);
let (a3, cc) = subborrow_u64(a.0[3] ^ sf, sf, cc);
let a4 = (cc as u64).wrapping_neg();
let (b0, cc) = subborrow_u64(b.0[0] ^ sg, sg, 0);
let (b1, cc) = subborrow_u64(b.0[1] ^ sg, sg, cc);
let (b2, cc) = subborrow_u64(b.0[2] ^ sg, sg, cc);
let (b3, cc) = subborrow_u64(b.0[3] ^ sg, sg, cc);
let b4 = (cc as u64).wrapping_neg();
let (d0, t) = umull_x2(a0, f, b0, g);
let (d1, t) = umull_x2_add(a1, f, b1, g, t);
let (d2, t) = umull_x2_add(a2, f, b2, g, t);
let (d3, t) = umull_x2_add(a3, f, b3, g, t);
let d4 = t.wrapping_sub(a4 & f).wrapping_sub(b4 & g);
let d0 = (d0 >> 31) | (d1 << 33);
let d1 = (d1 >> 31) | (d2 << 33);
let d2 = (d2 >> 31) | (d3 << 33);
let d3 = (d3 >> 31) | (d4 << 33);
let t = sgnw(d4);
let (d0, cc) = subborrow_u64(d0 ^ t, t, 0);
let (d1, cc) = subborrow_u64(d1 ^ t, t, cc);
let (d2, cc) = subborrow_u64(d2 ^ t, t, cc);
let (d3, _) = subborrow_u64(d3 ^ t, t, cc);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
t
}
#[inline(always)]
fn lindiv31abs(a: &Self, b: &Self, f: u64, g: u64) -> (Self, u64) {
let mut r = Self::ZERO;
let ng = r.set_lindiv31abs(a, b, f, g);
(r, ng)
}
fn set_div(&mut self, y: &Self) {
let mut a = *y;
a.set_normalized();
let mut b = Self([
Self::MOD0,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
]);
let mut u = *self;
let mut v = Self::ZERO;
for _ in 0..15 {
let m3 = a.0[3] | b.0[3];
let m2 = a.0[2] | b.0[2];
let m1 = a.0[1] | b.0[1];
let tnz3 = sgnw(m3 | m3.wrapping_neg());
let tnz2 = sgnw(m2 | m2.wrapping_neg()) & !tnz3;
let tnz1 = sgnw(m1 | m1.wrapping_neg()) & !tnz3 & !tnz2;
let tnzm = (m3 & tnz3) | (m2 & tnz2) | (m1 & tnz1);
let tnza = (a.0[3] & tnz3) | (a.0[2] & tnz2) | (a.0[1] & tnz1);
let tnzb = (b.0[3] & tnz3) | (b.0[2] & tnz2) | (b.0[1] & tnz1);
let snza = (a.0[2] & tnz3) | (a.0[1] & tnz2) | (a.0[0] & tnz1);
let snzb = (b.0[2] & tnz3) | (b.0[1] & tnz2) | (b.0[0] & tnz1);
let s = lzcnt(tnzm);
let sm = (31_i32.wrapping_sub(s as i32) >> 31) as u64;
let tnza = tnza ^ (sm & (tnza ^ ((tnza << 32) | (snza >> 32))));
let tnzb = tnzb ^ (sm & (tnzb ^ ((tnzb << 32) | (snzb >> 32))));
let s = s - (32 & (sm as u32));
let tnza = tnza << s;
let tnzb = tnzb << s;
let tzx = !(tnz1 | tnz2 | tnz3);
let tnza = tnza | (a.0[0] & tzx);
let tnzb = tnzb | (b.0[0] & tzx);
let mut xa = (a.0[0] & 0x7FFFFFFF) | (tnza & 0xFFFFFFFF80000000);
let mut xb = (b.0[0] & 0x7FFFFFFF) | (tnzb & 0xFFFFFFFF80000000);
let mut fg0 = 1u64;
let mut fg1 = 1u64 << 32;
for _ in 0..31 {
let a_odd = (xa & 1).wrapping_neg();
let (_, cc) = subborrow_u64(xa, xb, 0);
let swap = a_odd & (cc as u64).wrapping_neg();
let t1 = swap & (xa ^ xb);
xa ^= t1;
xb ^= t1;
let t2 = swap & (fg0 ^ fg1);
fg0 ^= t2;
fg1 ^= t2;
xa = xa.wrapping_sub(a_odd & xb);
fg0 = fg0.wrapping_sub(a_odd & fg1);
xa >>= 1;
fg1 <<= 1;
}
fg0 = fg0.wrapping_add(0x7FFFFFFF7FFFFFFF);
fg1 = fg1.wrapping_add(0x7FFFFFFF7FFFFFFF);
let f0 = (fg0 & 0xFFFFFFFF).wrapping_sub(0x7FFFFFFF);
let g0 = (fg0 >> 32).wrapping_sub(0x7FFFFFFF);
let f1 = (fg1 & 0xFFFFFFFF).wrapping_sub(0x7FFFFFFF);
let g1 = (fg1 >> 32).wrapping_sub(0x7FFFFFFF);
let (na, nega) = Self::lindiv31abs(&a, &b, f0, g0);
let (nb, negb) = Self::lindiv31abs(&a, &b, f1, g1);
let f0 = (f0 ^ nega).wrapping_sub(nega);
let g0 = (g0 ^ nega).wrapping_sub(nega);
let f1 = (f1 ^ negb).wrapping_sub(negb);
let g1 = (g1 ^ negb).wrapping_sub(negb);
let nu = Self::lin(&u, &v, f0, g0);
let nv = Self::lin(&u, &v, f1, g1);
a = na;
b = nb;
u = nu;
v = nv;
}
let mut xa = a.0[0];
let mut xb = b.0[0];
let mut f0 = 1u64;
let mut g0 = 0u64;
let mut f1 = 0u64;
let mut g1 = 1u64;
for _ in 0..45 {
let a_odd = (xa & 1).wrapping_neg();
let (_, cc) = subborrow_u64(xa, xb, 0);
let swap = a_odd & (cc as u64).wrapping_neg();
let t1 = swap & (xa ^ xb);
xa ^= t1;
xb ^= t1;
let t2 = swap & (f0 ^ f1);
f0 ^= t2;
f1 ^= t2;
let t3 = swap & (g0 ^ g1);
g0 ^= t3;
g1 ^= t3;
xa = xa.wrapping_sub(a_odd & xb);
f0 = f0.wrapping_sub(a_odd & f1);
g0 = g0.wrapping_sub(a_odd & g1);
xa >>= 1;
f1 <<= 1;
g1 <<= 1;
}
self.set_lin(&u, &v, f1, g1);
self.set_mul(&Self::INVT510);
}
pub fn batch_invert(xx: &mut [Self]) {
let n = xx.len();
let mut i = 0;
while i < n {
let blen = if (n - i) > 200 { 200 } else { n - i };
let mut tt = [Self::ZERO; 200];
tt[0] = xx[i];
let zz0 = tt[0].iszero();
tt[0].set_cond(&Self::ONE, zz0);
for j in 1..blen {
tt[j] = xx[i + j];
tt[j].set_cond(&Self::ONE, tt[j].iszero());
tt[j] *= tt[j - 1];
}
let mut k = Self::ONE / tt[blen - 1];
for j in (1..blen).rev() {
let mut x = xx[i + j];
let zz = x.iszero();
x.set_cond(&Self::ONE, zz);
xx[i + j].set_cond(&(k * tt[j - 1]), !zz);
k *= x;
}
xx[i].set_cond(&k, !zz0);
i += blen;
}
}
pub fn legendre(self) -> i32 {
let mut a = self;
a.set_normalized();
let mut b = Self([
Self::MOD0,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
]);
let mut ls = 0u64;
for _ in 0..15 {
let m3 = a.0[3] | b.0[3];
let m2 = a.0[2] | b.0[2];
let m1 = a.0[1] | b.0[1];
let tnz3 = sgnw(m3 | m3.wrapping_neg());
let tnz2 = sgnw(m2 | m2.wrapping_neg()) & !tnz3;
let tnz1 = sgnw(m1 | m1.wrapping_neg()) & !tnz3 & !tnz2;
let tnzm = (m3 & tnz3) | (m2 & tnz2) | (m1 & tnz1);
let tnza = (a.0[3] & tnz3) | (a.0[2] & tnz2) | (a.0[1] & tnz1);
let tnzb = (b.0[3] & tnz3) | (b.0[2] & tnz2) | (b.0[1] & tnz1);
let snza = (a.0[2] & tnz3) | (a.0[1] & tnz2) | (a.0[0] & tnz1);
let snzb = (b.0[2] & tnz3) | (b.0[1] & tnz2) | (b.0[0] & tnz1);
let s = lzcnt(tnzm);
let sm = (31_i32.wrapping_sub(s as i32) >> 31) as u64;
let tnza = tnza ^ (sm & (tnza ^ ((tnza << 32) | (snza >> 32))));
let tnzb = tnzb ^ (sm & (tnzb ^ ((tnzb << 32) | (snzb >> 32))));
let s = s - (32 & (sm as u32));
let tnza = tnza << s;
let tnzb = tnzb << s;
let tzx = !(tnz1 | tnz2 | tnz3);
let tnza = tnza | (a.0[0] & tzx);
let tnzb = tnzb | (b.0[0] & tzx);
let mut xa = (a.0[0] & 0x7FFFFFFF) | (tnza & 0xFFFFFFFF80000000);
let mut xb = (b.0[0] & 0x7FFFFFFF) | (tnzb & 0xFFFFFFFF80000000);
let mut fg0 = 1u64;
let mut fg1 = 1u64 << 32;
for _ in 0..29 {
let a_odd = (xa & 1).wrapping_neg();
let (_, cc) = subborrow_u64(xa, xb, 0);
let swap = a_odd & (cc as u64).wrapping_neg();
ls ^= swap & ((xa & xb) >> 1);
let t1 = swap & (xa ^ xb);
xa ^= t1;
xb ^= t1;
let t2 = swap & (fg0 ^ fg1);
fg0 ^= t2;
fg1 ^= t2;
xa = xa.wrapping_sub(a_odd & xb);
fg0 = fg0.wrapping_sub(a_odd & fg1);
xa >>= 1;
fg1 <<= 1;
ls ^= xb.wrapping_add(2) >> 2;
}
let fg0z = fg0.wrapping_add(0x7FFFFFFF7FFFFFFF);
let fg1z = fg1.wrapping_add(0x7FFFFFFF7FFFFFFF);
let f0 = (fg0z & 0xFFFFFFFF).wrapping_sub(0x7FFFFFFF);
let g0 = (fg0z >> 32).wrapping_sub(0x7FFFFFFF);
let f1 = (fg1z & 0xFFFFFFFF).wrapping_sub(0x7FFFFFFF);
let g1 = (fg1z >> 32).wrapping_sub(0x7FFFFFFF);
let mut a0 = a.0[0].wrapping_mul(f0)
.wrapping_add(b.0[0].wrapping_mul(g0)) >> 29;
let mut b0 = a.0[0].wrapping_mul(f1)
.wrapping_add(b.0[0].wrapping_mul(g1)) >> 29;
for _ in 0..2 {
let a_odd = (xa & 1).wrapping_neg();
let (_, cc) = subborrow_u64(xa, xb, 0);
let swap = a_odd & (cc as u64).wrapping_neg();
ls ^= swap & ((a0 & b0) >> 1);
let t1 = swap & (xa ^ xb);
xa ^= t1;
xb ^= t1;
let t2 = swap & (fg0 ^ fg1);
fg0 ^= t2;
fg1 ^= t2;
let t3 = swap & (a0 ^ b0);
a0 ^= t3;
b0 ^= t3;
xa = xa.wrapping_sub(a_odd & xb);
fg0 = fg0.wrapping_sub(a_odd & fg1);
a0 = a0.wrapping_sub(a_odd & b0);
xa >>= 1;
fg1 <<= 1;
a0 >>= 1;
ls ^= b0.wrapping_add(2) >> 2;
}
fg0 = fg0.wrapping_add(0x7FFFFFFF7FFFFFFF);
fg1 = fg1.wrapping_add(0x7FFFFFFF7FFFFFFF);
let f0 = (fg0 & 0xFFFFFFFF).wrapping_sub(0x7FFFFFFF);
let g0 = (fg0 >> 32).wrapping_sub(0x7FFFFFFF);
let f1 = (fg1 & 0xFFFFFFFF).wrapping_sub(0x7FFFFFFF);
let g1 = (fg1 >> 32).wrapping_sub(0x7FFFFFFF);
let (na, nega) = Self::lindiv31abs(&a, &b, f0, g0);
let (nb, _) = Self::lindiv31abs(&a, &b, f1, g1);
ls ^= nega & (nb.0[0] >> 1);
a = na;
b = nb;
}
let mut xa = a.0[0];
let mut xb = b.0[0];
for _ in 0..45 {
let a_odd = (xa & 1).wrapping_neg();
let (_, cc) = subborrow_u64(xa, xb, 0);
let swap = a_odd & (cc as u64).wrapping_neg();
ls ^= swap & ((xa & xb) >> 1);
let t1 = swap & (xa ^ xb);
xa ^= t1;
xb ^= t1;
xa = xa.wrapping_sub(a_odd & xb);
xa >>= 1;
ls ^= xb.wrapping_add(2) >> 2;
}
let r = 1u32.wrapping_sub(((ls as u32) & 1) << 1);
(r & !(self.iszero() as u32)) as i32
}
fn set_sqrt(&mut self) -> u32 {
let x = *self;
let xx = x.square();
let x2 = xx * x;
let x4 = x2.xsquare(2) * x2;
let x8 = x4.xsquare(4) * x4;
let x16 = x8.xsquare(8) * x8;
let x22 = (x16.xsquare(4) * x4).xsquare(2) * x2;
let x44 = x22.xsquare(22) * x22;
let x110 = (x44.xsquare(44) * x44).xsquare(22) * x22;
let x220 = x110.xsquare(110) * x110;
let x223 = (x220.xsquare(2) * x2).square() * x;
let mut y = ((x223.xsquare(23) * x22).xsquare(6) * x2).xsquare(2);
y.set_normalized();
y.set_cond(&-y, ((y.0[0] as u32) & 1).wrapping_neg());
let r = y.square().equals(*self);
y.set_cond(&Self::ZERO, !r);
*self = y;
r
}
#[inline(always)]
pub fn sqrt(self) -> (Self, u32) {
let mut x = self;
let r = x.set_sqrt();
(x, r)
}
#[inline(always)]
pub fn equals(self, rhs: Self) -> u32 {
(self - rhs).iszero()
}
#[inline]
pub fn iszero(self) -> u32 {
let a0 = self.0[0];
let a1 = self.0[1];
let a2 = self.0[2];
let a3 = self.0[3];
let t0 = a0 | a1 | a2 | a3;
let t1 = a0.wrapping_add(Self::T256_MINUS_Q) | !a1 | !a2 | !a3;
let r = (t0 | t0.wrapping_neg()) & (t1 | t1.wrapping_neg());
((r >> 63) as u32).wrapping_sub(1)
}
#[inline(always)]
fn set_decode32_reduce(&mut self, buf: &[u8]) {
debug_assert!(buf.len() == 32);
self.0[0] = u64::from_le_bytes(*<&[u8; 8]>::try_from(&buf[ 0.. 8]).unwrap());
self.0[1] = u64::from_le_bytes(*<&[u8; 8]>::try_from(&buf[ 8..16]).unwrap());
self.0[2] = u64::from_le_bytes(*<&[u8; 8]>::try_from(&buf[16..24]).unwrap());
self.0[3] = u64::from_le_bytes(*<&[u8; 8]>::try_from(&buf[24..32]).unwrap());
}
#[inline(always)]
pub fn encode(self) -> [u8; 32] {
let mut r = self;
r.set_normalized();
let mut d = [0u8; 32];
d[ 0.. 8].copy_from_slice(&r.0[0].to_le_bytes());
d[ 8..16].copy_from_slice(&r.0[1].to_le_bytes());
d[16..24].copy_from_slice(&r.0[2].to_le_bytes());
d[24..32].copy_from_slice(&r.0[3].to_le_bytes());
d
}
#[inline(always)]
pub fn encode32(self) -> [u8; 32] {
self.encode()
}
#[inline]
pub fn set_decode_ct(&mut self, buf: &[u8]) -> u32 {
*self = Self::ZERO;
if buf.len() != 32 {
return 0;
}
self.set_decode32_reduce(buf);
let (_, cc) = subborrow_u64(self.0[0], Self::MOD0, 0);
let (_, cc) = subborrow_u64(self.0[1], 0xFFFFFFFFFFFFFFFF, cc);
let (_, cc) = subborrow_u64(self.0[2], 0xFFFFFFFFFFFFFFFF, cc);
let (_, cc) = subborrow_u64(self.0[3], 0xFFFFFFFFFFFFFFFF, cc);
let cc = (cc as u64).wrapping_neg();
self.0[0] &= cc;
self.0[1] &= cc;
self.0[2] &= cc;
self.0[3] &= cc;
cc as u32
}
#[inline(always)]
pub fn decode_ct(buf: &[u8]) -> (Self, u32) {
let mut r = Self::ZERO;
let cc = r.set_decode_ct(buf);
(r, cc)
}
#[inline(always)]
pub fn decode32(buf: &[u8]) -> (Self, u32) {
Self::decode_ct(buf)
}
#[inline(always)]
pub fn decode(buf: &[u8]) -> Option<Self> {
let (r, cc) = Self::decode_ct(buf);
if cc != 0 {
Some(r)
} else {
None
}
}
pub fn set_decode_reduce(&mut self, buf: &[u8]) {
*self = Self::ZERO;
let mut n = buf.len();
if n == 0 {
return;
}
if (n & 31) != 0 {
let k = n & !(31 as usize);
let mut tmp = [0u8; 32];
tmp[..(n - k)].copy_from_slice(&buf[k..]);
n = k;
self.set_decode32_reduce(&tmp);
} else {
n -= 32;
self.set_decode32_reduce(&buf[n..]);
}
while n > 0 {
let k = n - 32;
let e0 = u64::from_le_bytes(*<&[u8; 8]>
::try_from(&buf[k ..k + 8]).unwrap());
let e1 = u64::from_le_bytes(*<&[u8; 8]>
::try_from(&buf[k + 8..k + 16]).unwrap());
let e2 = u64::from_le_bytes(*<&[u8; 8]>
::try_from(&buf[k + 16..k + 24]).unwrap());
let e3 = u64::from_le_bytes(*<&[u8; 8]>
::try_from(&buf[k + 24..k + 32]).unwrap());
let (d0, h0) = umull(self.0[0], Self::T256_MINUS_Q);
let (d0, cc) = addcarry_u64(d0, e0, 0);
let (d1, h1) = umull(self.0[1], Self::T256_MINUS_Q);
let (d1, cc) = addcarry_u64(d1, e1, cc);
let (d2, h2) = umull(self.0[2], Self::T256_MINUS_Q);
let (d2, cc) = addcarry_u64(d2, e2, cc);
let (d3, h3) = umull(self.0[3], Self::T256_MINUS_Q);
let (d3, cc) = addcarry_u64(d3, e3, cc);
let (h3, _) = addcarry_u64(h3, 0, cc);
let (lo, hi) = umull(h3, Self::T256_MINUS_Q);
let (d0, cc) = addcarry_u64(d0, lo, 0);
let (d1, cc) = addcarry_u64(d1, h0 + hi, cc);
let (d2, cc) = addcarry_u64(d2, h1, cc);
let (d3, cc) = addcarry_u64(d3, h2, cc);
let w = (cc as u64).wrapping_neg();
let (d0, cc) = addcarry_u64(d0, w & Self::T256_MINUS_Q, 0);
let (d1, cc) = addcarry_u64(d1, 0, cc);
let (d2, cc) = addcarry_u64(d2, 0, cc);
let (d3, _) = addcarry_u64(d3, 0, cc);
self.0[0] = d0;
self.0[1] = d1;
self.0[2] = d2;
self.0[3] = d3;
n = k;
}
}
#[inline(always)]
pub fn decode_reduce(buf: &[u8]) -> Self {
let mut r = Self::ZERO;
r.set_decode_reduce(buf);
r
}
}
impl Add<GFsecp256k1> for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn add(self, other: GFsecp256k1) -> GFsecp256k1 {
let mut r = self;
r.set_add(&other);
r
}
}
impl Add<&GFsecp256k1> for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn add(self, other: &GFsecp256k1) -> GFsecp256k1 {
let mut r = self;
r.set_add(other);
r
}
}
impl Add<GFsecp256k1> for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn add(self, other: GFsecp256k1) -> GFsecp256k1 {
let mut r = *self;
r.set_add(&other);
r
}
}
impl Add<&GFsecp256k1> for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn add(self, other: &GFsecp256k1) -> GFsecp256k1 {
let mut r = *self;
r.set_add(other);
r
}
}
impl AddAssign<GFsecp256k1> for GFsecp256k1 {
#[inline(always)]
fn add_assign(&mut self, other: GFsecp256k1) {
self.set_add(&other);
}
}
impl AddAssign<&GFsecp256k1> for GFsecp256k1 {
#[inline(always)]
fn add_assign(&mut self, other: &GFsecp256k1) {
self.set_add(other);
}
}
impl Div<GFsecp256k1> for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn div(self, other: GFsecp256k1) -> GFsecp256k1 {
let mut r = self;
r.set_div(&other);
r
}
}
impl Div<&GFsecp256k1> for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn div(self, other: &GFsecp256k1) -> GFsecp256k1 {
let mut r = self;
r.set_div(other);
r
}
}
impl Div<GFsecp256k1> for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn div(self, other: GFsecp256k1) -> GFsecp256k1 {
let mut r = *self;
r.set_div(&other);
r
}
}
impl Div<&GFsecp256k1> for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn div(self, other: &GFsecp256k1) -> GFsecp256k1 {
let mut r = *self;
r.set_div(other);
r
}
}
impl DivAssign<GFsecp256k1> for GFsecp256k1 {
#[inline(always)]
fn div_assign(&mut self, other: GFsecp256k1) {
self.set_div(&other);
}
}
impl DivAssign<&GFsecp256k1> for GFsecp256k1 {
#[inline(always)]
fn div_assign(&mut self, other: &GFsecp256k1) {
self.set_div(other);
}
}
impl Mul<GFsecp256k1> for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn mul(self, other: GFsecp256k1) -> GFsecp256k1 {
let mut r = self;
r.set_mul(&other);
r
}
}
impl Mul<&GFsecp256k1> for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn mul(self, other: &GFsecp256k1) -> GFsecp256k1 {
let mut r = self;
r.set_mul(other);
r
}
}
impl Mul<GFsecp256k1> for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn mul(self, other: GFsecp256k1) -> GFsecp256k1 {
let mut r = *self;
r.set_mul(&other);
r
}
}
impl Mul<&GFsecp256k1> for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn mul(self, other: &GFsecp256k1) -> GFsecp256k1 {
let mut r = *self;
r.set_mul(other);
r
}
}
impl MulAssign<GFsecp256k1> for GFsecp256k1 {
#[inline(always)]
fn mul_assign(&mut self, other: GFsecp256k1) {
self.set_mul(&other);
}
}
impl MulAssign<&GFsecp256k1> for GFsecp256k1 {
#[inline(always)]
fn mul_assign(&mut self, other: &GFsecp256k1) {
self.set_mul(other);
}
}
impl Neg for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn neg(self) -> GFsecp256k1 {
let mut r = self;
r.set_neg();
r
}
}
impl Neg for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn neg(self) -> GFsecp256k1 {
let mut r = *self;
r.set_neg();
r
}
}
impl Sub<GFsecp256k1> for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn sub(self, other: GFsecp256k1) -> GFsecp256k1 {
let mut r = self;
r.set_sub(&other);
r
}
}
impl Sub<&GFsecp256k1> for GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn sub(self, other: &GFsecp256k1) -> GFsecp256k1 {
let mut r = self;
r.set_sub(other);
r
}
}
impl Sub<GFsecp256k1> for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn sub(self, other: GFsecp256k1) -> GFsecp256k1 {
let mut r = *self;
r.set_sub(&other);
r
}
}
impl Sub<&GFsecp256k1> for &GFsecp256k1 {
type Output = GFsecp256k1;
#[inline(always)]
fn sub(self, other: &GFsecp256k1) -> GFsecp256k1 {
let mut r = *self;
r.set_sub(other);
r
}
}
impl SubAssign<GFsecp256k1> for GFsecp256k1 {
#[inline(always)]
fn sub_assign(&mut self, other: GFsecp256k1) {
self.set_sub(&other);
}
}
impl SubAssign<&GFsecp256k1> for GFsecp256k1 {
#[inline(always)]
fn sub_assign(&mut self, other: &GFsecp256k1) {
self.set_sub(other);
}
}
#[cfg(test)]
mod tests {
use super::{GFsecp256k1};
use num_bigint::{BigInt, Sign};
use sha2::{Sha256, Digest};
fn check_gf_ops(va: &[u8], vb: &[u8], vx: &[u8]) {
let zp = BigInt::from_slice(Sign::Plus, &[
0xFFFFFC2Fu32, 0xFFFFFFFEu32, 0xFFFFFFFFu32, 0xFFFFFFFFu32,
0xFFFFFFFFu32, 0xFFFFFFFFu32, 0xFFFFFFFFu32, 0xFFFFFFFFu32,
]);
let zp4 = &zp << 2;
let mut a = GFsecp256k1::ZERO;
a.set_decode32_reduce(va);
let mut b = GFsecp256k1::ZERO;
b.set_decode32_reduce(vb);
let za = BigInt::from_bytes_le(Sign::Plus, va);
let zb = BigInt::from_bytes_le(Sign::Plus, vb);
let vc = a.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = &za % &zp;
assert!(zc == zd);
let c = a + b;
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za + &zb) % &zp;
assert!(zc == zd);
let c = a - b;
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = ((&zp4 + &za) - &zb) % &zp;
assert!(zc == zd);
let c = -a;
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&zp4 - &za) % &zp;
assert!(zc == zd);
let c = a * b;
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za * &zb) % &zp;
assert!(zc == zd);
let c = a.half();
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd: BigInt = ((&zp4 + (&zc << 1)) - &za) % &zp;
assert!(zd.sign() == Sign::NoSign);
let c = a.mul2();
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za << 1) % &zp;
assert!(zc == zd);
let c = a.mul4();
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za << 2) % &zp;
assert!(zc == zd);
let c = a.mul8();
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za << 3) % &zp;
assert!(zc == zd);
let c = a.mul16();
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za << 4) % &zp;
assert!(zc == zd);
let c = a.mul32();
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za << 5) % &zp;
assert!(zc == zd);
let x = b.0[1] as u16;
let c = a.mul_u16(x);
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za * x) % &zp;
assert!(zc == zd);
let c = a.square();
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = (&za * &za) % &zp;
assert!(zc == zd);
let (e, cc) = GFsecp256k1::decode_ct(va);
if cc != 0 {
assert!(cc == 0xFFFFFFFF);
assert!(e.encode() == va);
} else {
assert!(e.encode() == [0u8; 32]);
}
let mut tmp = [0u8; 96];
tmp[0..32].copy_from_slice(va);
tmp[32..64].copy_from_slice(vb);
tmp[64..96].copy_from_slice(vx);
for k in 0..97 {
let c = GFsecp256k1::decode_reduce(&tmp[0..k]);
let vc = c.encode();
let zc = BigInt::from_bytes_le(Sign::Plus, &vc);
let zd = BigInt::from_bytes_le(Sign::Plus, &tmp[0..k]) % &zp;
assert!(zc == zd);
}
let c = a / b;
let d = c * b;
if b.iszero() != 0 {
assert!(c.iszero() != 0);
} else {
assert!(a.equals(d) != 0);
}
}
fn test_gf(nqr: u16) {
let mut va = [0u8; 32];
let mut vb = [0u8; 32];
let mut vx = [0u8; 32];
check_gf_ops(&va, &vb, &vx);
assert!(GFsecp256k1::decode_reduce(&va).iszero() == 0xFFFFFFFF);
assert!(GFsecp256k1::decode_reduce(&va).equals(GFsecp256k1::decode_reduce(&vb)) == 0xFFFFFFFF);
assert!(GFsecp256k1::decode_reduce(&va).legendre() == 0);
for i in 0..32 {
va[i] = 0xFFu8;
vb[i] = 0xFFu8;
vx[i] = 0xFFu8;
}
check_gf_ops(&va, &vb, &vx);
assert!(GFsecp256k1::decode_reduce(&va).iszero() == 0);
assert!(GFsecp256k1::decode_reduce(&va).equals(GFsecp256k1::decode_reduce(&vb)) == 0xFFFFFFFF);
va[0..8].copy_from_slice(&0xFFFFFFFEFFFFFC2Fu64.to_le_bytes());
assert!(GFsecp256k1::decode_reduce(&va).iszero() == 0xFFFFFFFF);
let mut sh = Sha256::new();
for i in 0..300 {
sh.update(((3 * i + 0) as u64).to_le_bytes());
let va = sh.finalize_reset();
sh.update(((3 * i + 1) as u64).to_le_bytes());
let vb = sh.finalize_reset();
sh.update(((3 * i + 2) as u64).to_le_bytes());
let vx = sh.finalize_reset();
check_gf_ops(&va, &vb, &vx);
assert!(GFsecp256k1::decode_reduce(&va).iszero() == 0);
assert!(GFsecp256k1::decode_reduce(&va).equals(GFsecp256k1::decode_reduce(&vb)) == 0);
let s = GFsecp256k1::decode_reduce(&va).square();
let s2 = s.mul_u16(nqr);
assert!(s.legendre() == 1);
assert!(s2.legendre() == -1);
let (t, r) = s.sqrt();
assert!(r == 0xFFFFFFFF);
assert!(t.square().equals(s) == 0xFFFFFFFF);
assert!((t.encode()[0] & 1) == 0);
let (t2, r) = s2.sqrt();
assert!(r == 0);
assert!(t2.iszero() == 0xFFFFFFFF);
}
}
#[test]
fn gfsecp256k1_ops() {
test_gf(3);
}
#[test]
fn gfsecp256k1_batch_invert() {
let mut xx = [GFsecp256k1::ZERO; 300];
let mut sh = Sha256::new();
for i in 0..300 {
sh.update((i as u64).to_le_bytes());
let v = sh.finalize_reset();
xx[i] = GFsecp256k1::decode_reduce(&v);
}
xx[120] = GFsecp256k1::ZERO;
let mut yy = xx;
GFsecp256k1::batch_invert(&mut yy[..]);
for i in 0..300 {
if xx[i].iszero() != 0 {
assert!(yy[i].iszero() == 0xFFFFFFFF);
} else {
assert!((xx[i] * yy[i]).equals(GFsecp256k1::ONE) == 0xFFFFFFFF);
}
}
}
}