use core::ops::{Add, AddAssign, Mul, MulAssign, Neg};
use crunchy::unroll;
use subtle::Choice;
const SECP256K1_N: [u32; 8] = [
0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
];
const SECP256K1_N_C_0: u32 = !SECP256K1_N[0] + 1;
const SECP256K1_N_C_1: u32 = !SECP256K1_N[1];
const SECP256K1_N_C_2: u32 = !SECP256K1_N[2];
const SECP256K1_N_C_3: u32 = !SECP256K1_N[3];
const SECP256K1_N_C_4: u32 = 1;
const SECP256K1_N_H_0: u32 = 0x681B20A0;
const SECP256K1_N_H_1: u32 = 0xDFE92F46;
const SECP256K1_N_H_2: u32 = 0x57A4501D;
const SECP256K1_N_H_3: u32 = 0x5D576E73;
const SECP256K1_N_H_4: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_5: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_6: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_7: u32 = 0x7FFFFFFF;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Scalar(pub [u32; 8]);
impl Scalar {
pub fn clear(&mut self) {
unsafe {
core::ptr::write_volatile(&mut self.0, [0u32; 8]);
}
}
pub fn set_int(&mut self, v: u32) {
self.0 = [v, 0, 0, 0, 0, 0, 0, 0];
}
pub fn from_int(v: u32) -> Self {
let mut scalar = Self::default();
scalar.set_int(v);
scalar
}
pub fn bits(&self, offset: usize, count: usize) -> u32 {
debug_assert!((offset + count - 1) >> 5 == offset >> 5);
(self.0[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1)
}
pub fn bits_var(&self, offset: usize, count: usize) -> u32 {
debug_assert!(count < 32);
debug_assert!(offset + count <= 256);
if (offset + count - 1) >> 5 == offset >> 5 {
self.bits(offset, count)
} else {
debug_assert!((offset >> 5) + 1 < 8);
((self.0[offset >> 5] >> (offset & 0x1f))
| (self.0[(offset >> 5) + 1] << (32 - (offset & 0x1f))))
& ((1 << count) - 1)
}
}
#[must_use]
fn check_overflow(&self) -> Choice {
let mut yes: Choice = 0.into();
let mut no: Choice = 0.into();
no |= Choice::from((self.0[7] < SECP256K1_N[7]) as u8); no |= Choice::from((self.0[6] < SECP256K1_N[6]) as u8); no |= Choice::from((self.0[5] < SECP256K1_N[5]) as u8); no |= Choice::from((self.0[4] < SECP256K1_N[4]) as u8);
yes |= Choice::from((self.0[4] > SECP256K1_N[4]) as u8) & !no;
no |= Choice::from((self.0[3] < SECP256K1_N[3]) as u8) & !yes;
yes |= Choice::from((self.0[3] > SECP256K1_N[3]) as u8) & !no;
no |= Choice::from((self.0[2] < SECP256K1_N[2]) as u8) & !yes;
yes |= Choice::from((self.0[2] > SECP256K1_N[2]) as u8) & !no;
no |= Choice::from((self.0[1] < SECP256K1_N[1]) as u8) & !yes;
yes |= Choice::from((self.0[1] > SECP256K1_N[1]) as u8) & !no;
yes |= Choice::from((self.0[0] >= SECP256K1_N[0]) as u8) & !no;
yes
}
fn reduce(&mut self, overflow: Choice) {
let o = overflow.unwrap_u8() as u64;
let mut t: u64;
t = (self.0[0] as u64) + o * (SECP256K1_N_C_0 as u64);
self.0[0] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[1] as u64) + o * (SECP256K1_N_C_1 as u64);
self.0[1] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[2] as u64) + o * (SECP256K1_N_C_2 as u64);
self.0[2] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[3] as u64) + o * (SECP256K1_N_C_3 as u64);
self.0[3] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[4] as u64) + o * (SECP256K1_N_C_4 as u64);
self.0[4] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += self.0[5] as u64;
self.0[5] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += self.0[6] as u64;
self.0[6] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += self.0[7] as u64;
self.0[7] = (t & 0xFFFFFFFF) as u32;
}
pub fn cadd_bit(&mut self, mut bit: usize, flag: bool) {
let mut t: u64;
debug_assert!(bit < 256);
bit += if flag { 0 } else { usize::max_value() } & 0x100;
t = (self.0[0] as u64) + ((if (bit >> 5) == 0 { 1 } else { 0 }) << (bit & 0x1F));
self.0[0] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[1] as u64) + ((if (bit >> 5) == 1 { 1 } else { 0 }) << (bit & 0x1F));
self.0[1] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[2] as u64) + ((if (bit >> 5) == 2 { 1 } else { 0 }) << (bit & 0x1F));
self.0[2] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[3] as u64) + ((if (bit >> 5) == 3 { 1 } else { 0 }) << (bit & 0x1F));
self.0[3] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[4] as u64) + ((if (bit >> 5) == 4 { 1 } else { 0 }) << (bit & 0x1F));
self.0[4] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[5] as u64) + ((if (bit >> 5) == 5 { 1 } else { 0 }) << (bit & 0x1F));
self.0[5] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[6] as u64) + ((if (bit >> 5) == 6 { 1 } else { 0 }) << (bit & 0x1F));
self.0[6] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[7] as u64) + ((if (bit >> 5) == 7 { 1 } else { 0 }) << (bit & 0x1F));
self.0[7] = (t & 0xFFFFFFFF) as u32;
debug_assert!((t >> 32) == 0);
debug_assert!(!bool::from(self.check_overflow()));
}
#[must_use]
pub fn set_b32(&mut self, b32: &[u8; 32]) -> Choice {
self.0[0] = (b32[31] as u32)
| ((b32[30] as u32) << 8)
| ((b32[29] as u32) << 16)
| ((b32[28] as u32) << 24);
self.0[1] = (b32[27] as u32)
| ((b32[26] as u32) << 8)
| ((b32[25] as u32) << 16)
| ((b32[24] as u32) << 24);
self.0[2] = (b32[23] as u32)
| ((b32[22] as u32) << 8)
| ((b32[21] as u32) << 16)
| ((b32[20] as u32) << 24);
self.0[3] = (b32[19] as u32)
| ((b32[18] as u32) << 8)
| ((b32[17] as u32) << 16)
| ((b32[16] as u32) << 24);
self.0[4] = (b32[15] as u32)
| ((b32[14] as u32) << 8)
| ((b32[13] as u32) << 16)
| ((b32[12] as u32) << 24);
self.0[5] = (b32[11] as u32)
| ((b32[10] as u32) << 8)
| ((b32[9] as u32) << 16)
| ((b32[8] as u32) << 24);
self.0[6] = (b32[7] as u32)
| ((b32[6] as u32) << 8)
| ((b32[5] as u32) << 16)
| ((b32[4] as u32) << 24);
self.0[7] = (b32[3] as u32)
| ((b32[2] as u32) << 8)
| ((b32[1] as u32) << 16)
| ((b32[0] as u32) << 24);
let overflow = self.check_overflow();
self.reduce(overflow);
overflow
}
pub fn b32(&self) -> [u8; 32] {
let mut bin = [0u8; 32];
self.fill_b32(&mut bin);
bin
}
pub fn fill_b32(&self, bin: &mut [u8; 32]) {
bin[0] = (self.0[7] >> 24) as u8;
bin[1] = (self.0[7] >> 16) as u8;
bin[2] = (self.0[7] >> 8) as u8;
bin[3] = (self.0[7]) as u8;
bin[4] = (self.0[6] >> 24) as u8;
bin[5] = (self.0[6] >> 16) as u8;
bin[6] = (self.0[6] >> 8) as u8;
bin[7] = (self.0[6]) as u8;
bin[8] = (self.0[5] >> 24) as u8;
bin[9] = (self.0[5] >> 16) as u8;
bin[10] = (self.0[5] >> 8) as u8;
bin[11] = (self.0[5]) as u8;
bin[12] = (self.0[4] >> 24) as u8;
bin[13] = (self.0[4] >> 16) as u8;
bin[14] = (self.0[4] >> 8) as u8;
bin[15] = (self.0[4]) as u8;
bin[16] = (self.0[3] >> 24) as u8;
bin[17] = (self.0[3] >> 16) as u8;
bin[18] = (self.0[3] >> 8) as u8;
bin[19] = (self.0[3]) as u8;
bin[20] = (self.0[2] >> 24) as u8;
bin[21] = (self.0[2] >> 16) as u8;
bin[22] = (self.0[2] >> 8) as u8;
bin[23] = (self.0[2]) as u8;
bin[24] = (self.0[1] >> 24) as u8;
bin[25] = (self.0[1] >> 16) as u8;
bin[26] = (self.0[1] >> 8) as u8;
bin[27] = (self.0[1]) as u8;
bin[28] = (self.0[0] >> 24) as u8;
bin[29] = (self.0[0] >> 16) as u8;
bin[30] = (self.0[0] >> 8) as u8;
bin[31] = (self.0[0]) as u8;
}
pub fn is_zero(&self) -> bool {
(self.0[0]
| self.0[1]
| self.0[2]
| self.0[3]
| self.0[4]
| self.0[5]
| self.0[6]
| self.0[7])
== 0
}
pub fn is_one(&self) -> bool {
((self.0[0] ^ 1)
| self.0[1]
| self.0[2]
| self.0[3]
| self.0[4]
| self.0[5]
| self.0[6]
| self.0[7])
== 0
}
pub fn is_high(&self) -> bool {
let mut yes: Choice = 0.into();
let mut no: Choice = 0.into();
no |= Choice::from((self.0[7] < SECP256K1_N_H_7) as u8);
yes |= Choice::from((self.0[7] > SECP256K1_N_H_7) as u8) & !no;
no |= Choice::from((self.0[6] < SECP256K1_N_H_6) as u8) & !yes; no |= Choice::from((self.0[5] < SECP256K1_N_H_5) as u8) & !yes; no |= Choice::from((self.0[4] < SECP256K1_N_H_4) as u8) & !yes; no |= Choice::from((self.0[3] < SECP256K1_N_H_3) as u8) & !yes;
yes |= Choice::from((self.0[3] > SECP256K1_N_H_3) as u8) & !no;
no |= Choice::from((self.0[2] < SECP256K1_N_H_2) as u8) & !yes;
yes |= Choice::from((self.0[2] > SECP256K1_N_H_2) as u8) & !no;
no |= Choice::from((self.0[1] < SECP256K1_N_H_1) as u8) & !yes;
yes |= Choice::from((self.0[1] > SECP256K1_N_H_1) as u8) & !no;
yes |= Choice::from((self.0[0] >= SECP256K1_N_H_0) as u8) & !no;
yes.into()
}
pub fn cond_neg_assign(&mut self, flag: Choice) {
let mask = u32::max_value() * flag.unwrap_u8() as u32;
let nonzero = 0xFFFFFFFFu64 * !self.is_zero() as u64;
let mut t = 1u64 * flag.unwrap_u8() as u64;
unroll! {
for i in 0..8 {
t += (self.0[i] ^ mask) as u64 + (SECP256K1_N[i] & mask) as u64;
self.0[i] = (t & nonzero) as u32;
t >>= 32;
}
}
let _ = t;
}
}
macro_rules! define_ops {
($c0: ident, $c1: ident, $c2: ident) => {
#[allow(unused_macros)]
macro_rules! muladd {
($a: expr, $b: expr) => {
let a = $a;
let b = $b;
let t = (a as u64) * (b as u64);
let mut th = (t >> 32) as u32;
let tl = t as u32;
$c0 = $c0.wrapping_add(tl);
th = th.wrapping_add(if $c0 < tl { 1 } else { 0 });
$c1 = $c1.wrapping_add(th);
$c2 = $c2.wrapping_add(if $c1 < th { 1 } else { 0 });
debug_assert!($c1 >= th || $c2 != 0);
};
}
#[allow(unused_macros)]
macro_rules! muladd_fast {
($a: expr, $b: expr) => {
let a = $a;
let b = $b;
let t = (a as u64) * (b as u64);
let mut th = (t >> 32) as u32;
let tl = t as u32;
$c0 = $c0.wrapping_add(tl);
th = th.wrapping_add(if $c0 < tl { 1 } else { 0 });
$c1 = $c1.wrapping_add(th);
debug_assert!($c1 >= th);
};
}
#[allow(unused_macros)]
macro_rules! muladd2 {
($a: expr, $b: expr) => {
let a = $a;
let b = $b;
let t = (a as u64) * (b as u64);
let th = (t >> 32) as u32;
let tl = t as u32;
let mut th2 = th.wrapping_add(th);
$c2 = $c2.wrapping_add(if th2 < th { 1 } else { 0 });
debug_assert!(th2 >= th || $c2 != 0);
let tl2 = tl.wrapping_add(tl);
th2 = th2.wrapping_add(if tl2 < tl { 1 } else { 0 });
$c0 = $c0.wrapping_add(tl2);
th2 = th2.wrapping_add(if $c0 < tl2 { 1 } else { 0 });
$c2 = $c2.wrapping_add(if $c0 < tl2 && th2 == 0 { 1 } else { 0 });
debug_assert!($c0 >= tl2 || th2 != 0 || $c2 != 0);
$c1 = $c1.wrapping_add(th2);
$c2 = $c2.wrapping_add(if $c1 < th2 { 1 } else { 0 });
debug_assert!($c1 >= th2 || $c2 != 0);
};
}
#[allow(unused_macros)]
macro_rules! sumadd {
($a: expr) => {
let a = $a;
$c0 = $c0.wrapping_add(a);
let over = if $c0 < a { 1 } else { 0 };
$c1 = $c1.wrapping_add(over);
$c2 = $c2.wrapping_add(if $c1 < over { 1 } else { 0 });
};
}
#[allow(unused_macros)]
macro_rules! sumadd_fast {
($a: expr) => {
let a = $a;
$c0 = $c0.wrapping_add(a);
$c1 = $c1.wrapping_add(if $c0 < a { 1 } else { 0 });
debug_assert!($c1 != 0 || $c0 >= a);
debug_assert!($c2 == 0);
};
}
#[allow(unused_macros)]
macro_rules! extract {
() => {{
#[allow(unused_assignments)]
{
let n = $c0;
$c0 = $c1;
$c1 = $c2;
$c2 = 0;
n
}
}};
}
#[allow(unused_macros)]
macro_rules! extract_fast {
() => {{
#[allow(unused_assignments)]
{
let n = $c0;
$c0 = $c1;
$c1 = 0;
debug_assert!($c2 == 0);
n
}
}};
}
};
}
impl Scalar {
fn reduce_512(&mut self, l: &[u32; 16]) {
let (mut c0, mut c1, mut c2): (u32, u32, u32);
define_ops!(c0, c1, c2);
let mut c: u64;
let (n0, n1, n2, n3, n4, n5, n6, n7) =
(l[8], l[9], l[10], l[11], l[12], l[13], l[14], l[15]);
let (m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12): (
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
);
let (p0, p1, p2, p3, p4, p5, p6, p7, p8): (u32, u32, u32, u32, u32, u32, u32, u32, u32);
c0 = l[0];
c1 = 0;
c2 = 0;
muladd_fast!(n0, SECP256K1_N_C_0);
m0 = extract_fast!();
sumadd_fast!(l[1]);
muladd!(n1, SECP256K1_N_C_0);
muladd!(n0, SECP256K1_N_C_1);
m1 = extract!();
sumadd!(l[2]);
muladd!(n2, SECP256K1_N_C_0);
muladd!(n1, SECP256K1_N_C_1);
muladd!(n0, SECP256K1_N_C_2);
m2 = extract!();
sumadd!(l[3]);
muladd!(n3, SECP256K1_N_C_0);
muladd!(n2, SECP256K1_N_C_1);
muladd!(n1, SECP256K1_N_C_2);
muladd!(n0, SECP256K1_N_C_3);
m3 = extract!();
sumadd!(l[4]);
muladd!(n4, SECP256K1_N_C_0);
muladd!(n3, SECP256K1_N_C_1);
muladd!(n2, SECP256K1_N_C_2);
muladd!(n1, SECP256K1_N_C_3);
sumadd!(n0);
m4 = extract!();
sumadd!(l[5]);
muladd!(n5, SECP256K1_N_C_0);
muladd!(n4, SECP256K1_N_C_1);
muladd!(n3, SECP256K1_N_C_2);
muladd!(n2, SECP256K1_N_C_3);
sumadd!(n1);
m5 = extract!();
sumadd!(l[6]);
muladd!(n6, SECP256K1_N_C_0);
muladd!(n5, SECP256K1_N_C_1);
muladd!(n4, SECP256K1_N_C_2);
muladd!(n3, SECP256K1_N_C_3);
sumadd!(n2);
m6 = extract!();
sumadd!(l[7]);
muladd!(n7, SECP256K1_N_C_0);
muladd!(n6, SECP256K1_N_C_1);
muladd!(n5, SECP256K1_N_C_2);
muladd!(n4, SECP256K1_N_C_3);
sumadd!(n3);
m7 = extract!();
muladd!(n7, SECP256K1_N_C_1);
muladd!(n6, SECP256K1_N_C_2);
muladd!(n5, SECP256K1_N_C_3);
sumadd!(n4);
m8 = extract!();
muladd!(n7, SECP256K1_N_C_2);
muladd!(n6, SECP256K1_N_C_3);
sumadd!(n5);
m9 = extract!();
muladd!(n7, SECP256K1_N_C_3);
sumadd!(n6);
m10 = extract!();
sumadd_fast!(n7);
m11 = extract_fast!();
debug_assert!(c0 <= 1);
m12 = c0;
c0 = m0;
c1 = 0;
c2 = 0;
muladd_fast!(m8, SECP256K1_N_C_0);
p0 = extract_fast!();
sumadd_fast!(m1);
muladd!(m9, SECP256K1_N_C_0);
muladd!(m8, SECP256K1_N_C_1);
p1 = extract!();
sumadd!(m2);
muladd!(m10, SECP256K1_N_C_0);
muladd!(m9, SECP256K1_N_C_1);
muladd!(m8, SECP256K1_N_C_2);
p2 = extract!();
sumadd!(m3);
muladd!(m11, SECP256K1_N_C_0);
muladd!(m10, SECP256K1_N_C_1);
muladd!(m9, SECP256K1_N_C_2);
muladd!(m8, SECP256K1_N_C_3);
p3 = extract!();
sumadd!(m4);
muladd!(m12, SECP256K1_N_C_0);
muladd!(m11, SECP256K1_N_C_1);
muladd!(m10, SECP256K1_N_C_2);
muladd!(m9, SECP256K1_N_C_3);
sumadd!(m8);
p4 = extract!();
sumadd!(m5);
muladd!(m12, SECP256K1_N_C_1);
muladd!(m11, SECP256K1_N_C_2);
muladd!(m10, SECP256K1_N_C_3);
sumadd!(m9);
p5 = extract!();
sumadd!(m6);
muladd!(m12, SECP256K1_N_C_2);
muladd!(m11, SECP256K1_N_C_3);
sumadd!(m10);
p6 = extract!();
sumadd_fast!(m7);
muladd_fast!(m12, SECP256K1_N_C_3);
sumadd_fast!(m11);
p7 = extract_fast!();
p8 = c0 + m12;
debug_assert!(p8 <= 2);
c = p0 as u64 + SECP256K1_N_C_0 as u64 * p8 as u64;
self.0[0] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p1 as u64 + SECP256K1_N_C_1 as u64 * p8 as u64;
self.0[1] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p2 as u64 + SECP256K1_N_C_2 as u64 * p8 as u64;
self.0[2] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p3 as u64 + SECP256K1_N_C_3 as u64 * p8 as u64;
self.0[3] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p4 as u64 + p8 as u64;
self.0[4] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p5 as u64;
self.0[5] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p6 as u64;
self.0[6] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p7 as u64;
self.0[7] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
let overflow = self.check_overflow();
self.reduce(Choice::from(c as u8) | overflow);
}
fn mul_512(&self, b: &Scalar, l: &mut [u32; 16]) {
let (mut c0, mut c1, mut c2): (u32, u32, u32) = (0, 0, 0);
define_ops!(c0, c1, c2);
muladd_fast!(self.0[0], b.0[0]);
l[0] = extract_fast!();
muladd!(self.0[0], b.0[1]);
muladd!(self.0[1], b.0[0]);
l[1] = extract!();
muladd!(self.0[0], b.0[2]);
muladd!(self.0[1], b.0[1]);
muladd!(self.0[2], b.0[0]);
l[2] = extract!();
muladd!(self.0[0], b.0[3]);
muladd!(self.0[1], b.0[2]);
muladd!(self.0[2], b.0[1]);
muladd!(self.0[3], b.0[0]);
l[3] = extract!();
muladd!(self.0[0], b.0[4]);
muladd!(self.0[1], b.0[3]);
muladd!(self.0[2], b.0[2]);
muladd!(self.0[3], b.0[1]);
muladd!(self.0[4], b.0[0]);
l[4] = extract!();
muladd!(self.0[0], b.0[5]);
muladd!(self.0[1], b.0[4]);
muladd!(self.0[2], b.0[3]);
muladd!(self.0[3], b.0[2]);
muladd!(self.0[4], b.0[1]);
muladd!(self.0[5], b.0[0]);
l[5] = extract!();
muladd!(self.0[0], b.0[6]);
muladd!(self.0[1], b.0[5]);
muladd!(self.0[2], b.0[4]);
muladd!(self.0[3], b.0[3]);
muladd!(self.0[4], b.0[2]);
muladd!(self.0[5], b.0[1]);
muladd!(self.0[6], b.0[0]);
l[6] = extract!();
muladd!(self.0[0], b.0[7]);
muladd!(self.0[1], b.0[6]);
muladd!(self.0[2], b.0[5]);
muladd!(self.0[3], b.0[4]);
muladd!(self.0[4], b.0[3]);
muladd!(self.0[5], b.0[2]);
muladd!(self.0[6], b.0[1]);
muladd!(self.0[7], b.0[0]);
l[7] = extract!();
muladd!(self.0[1], b.0[7]);
muladd!(self.0[2], b.0[6]);
muladd!(self.0[3], b.0[5]);
muladd!(self.0[4], b.0[4]);
muladd!(self.0[5], b.0[3]);
muladd!(self.0[6], b.0[2]);
muladd!(self.0[7], b.0[1]);
l[8] = extract!();
muladd!(self.0[2], b.0[7]);
muladd!(self.0[3], b.0[6]);
muladd!(self.0[4], b.0[5]);
muladd!(self.0[5], b.0[4]);
muladd!(self.0[6], b.0[3]);
muladd!(self.0[7], b.0[2]);
l[9] = extract!();
muladd!(self.0[3], b.0[7]);
muladd!(self.0[4], b.0[6]);
muladd!(self.0[5], b.0[5]);
muladd!(self.0[6], b.0[4]);
muladd!(self.0[7], b.0[3]);
l[10] = extract!();
muladd!(self.0[4], b.0[7]);
muladd!(self.0[5], b.0[6]);
muladd!(self.0[6], b.0[5]);
muladd!(self.0[7], b.0[4]);
l[11] = extract!();
muladd!(self.0[5], b.0[7]);
muladd!(self.0[6], b.0[6]);
muladd!(self.0[7], b.0[5]);
l[12] = extract!();
muladd!(self.0[6], b.0[7]);
muladd!(self.0[7], b.0[6]);
l[13] = extract!();
muladd_fast!(self.0[7], b.0[7]);
l[14] = extract_fast!();
debug_assert!(c1 == 0);
l[15] = c0;
}
fn sqr_512(&self, l: &mut [u32; 16]) {
let (mut c0, mut c1, mut c2): (u32, u32, u32) = (0, 0, 0);
define_ops!(c0, c1, c2);
muladd_fast!(self.0[0], self.0[0]);
l[0] = extract_fast!();
muladd2!(self.0[0], self.0[1]);
l[1] = extract!();
muladd2!(self.0[0], self.0[2]);
muladd!(self.0[1], self.0[1]);
l[2] = extract!();
muladd2!(self.0[0], self.0[3]);
muladd2!(self.0[1], self.0[2]);
l[3] = extract!();
muladd2!(self.0[0], self.0[4]);
muladd2!(self.0[1], self.0[3]);
muladd!(self.0[2], self.0[2]);
l[4] = extract!();
muladd2!(self.0[0], self.0[5]);
muladd2!(self.0[1], self.0[4]);
muladd2!(self.0[2], self.0[3]);
l[5] = extract!();
muladd2!(self.0[0], self.0[6]);
muladd2!(self.0[1], self.0[5]);
muladd2!(self.0[2], self.0[4]);
muladd!(self.0[3], self.0[3]);
l[6] = extract!();
muladd2!(self.0[0], self.0[7]);
muladd2!(self.0[1], self.0[6]);
muladd2!(self.0[2], self.0[5]);
muladd2!(self.0[3], self.0[4]);
l[7] = extract!();
muladd2!(self.0[1], self.0[7]);
muladd2!(self.0[2], self.0[6]);
muladd2!(self.0[3], self.0[5]);
muladd!(self.0[4], self.0[4]);
l[8] = extract!();
muladd2!(self.0[2], self.0[7]);
muladd2!(self.0[3], self.0[6]);
muladd2!(self.0[4], self.0[5]);
l[9] = extract!();
muladd2!(self.0[3], self.0[7]);
muladd2!(self.0[4], self.0[6]);
muladd!(self.0[5], self.0[5]);
l[10] = extract!();
muladd2!(self.0[4], self.0[7]);
muladd2!(self.0[5], self.0[6]);
l[11] = extract!();
muladd2!(self.0[5], self.0[7]);
muladd!(self.0[6], self.0[6]);
l[12] = extract!();
muladd2!(self.0[6], self.0[7]);
l[13] = extract!();
muladd_fast!(self.0[7], self.0[7]);
l[14] = extract_fast!();
debug_assert!(c1 == 0);
l[15] = c0;
}
pub fn mul_in_place(&mut self, a: &Scalar, b: &Scalar) {
let mut l = [0u32; 16];
a.mul_512(b, &mut l);
self.reduce_512(&l);
}
pub fn shr_int(&mut self, n: usize) -> u32 {
let ret: u32;
debug_assert!(n > 0);
debug_assert!(n < 16);
ret = self.0[0] & ((1 << n) - 1);
self.0[0] = (self.0[0] >> n) + (self.0[1] << (32 - n));
self.0[1] = (self.0[1] >> n) + (self.0[2] << (32 - n));
self.0[2] = (self.0[2] >> n) + (self.0[3] << (32 - n));
self.0[3] = (self.0[3] >> n) + (self.0[4] << (32 - n));
self.0[4] = (self.0[4] >> n) + (self.0[5] << (32 - n));
self.0[5] = (self.0[5] >> n) + (self.0[6] << (32 - n));
self.0[6] = (self.0[6] >> n) + (self.0[7] << (32 - n));
self.0[7] >>= n;
ret
}
pub fn sqr_in_place(&mut self, a: &Scalar) {
let mut l = [0u32; 16];
a.sqr_512(&mut l);
self.reduce_512(&l);
}
pub fn sqr(&self) -> Scalar {
let mut ret = Scalar::default();
ret.sqr_in_place(self);
ret
}
pub fn inv_in_place(&mut self, x: &Scalar) {
let u2 = x.sqr();
let x2 = u2 * *x;
let u5 = u2 * x2;
let x3 = u5 * u2;
let u9 = x3 * u2;
let u11 = u9 * u2;
let u13 = u11 * u2;
let mut x6 = u13.sqr();
x6 = x6.sqr();
x6 *= &u11;
let mut x8 = x6.sqr();
x8 = x8.sqr();
x8 *= &x2;
let mut x14 = x8.sqr();
for _ in 0..5 {
x14 = x14.sqr();
}
x14 *= &x6;
let mut x28 = x14.sqr();
for _ in 0..13 {
x28 = x28.sqr();
}
x28 *= &x14;
let mut x56 = x28.sqr();
for _ in 0..27 {
x56 = x56.sqr();
}
x56 *= &x28;
let mut x112 = x56.sqr();
for _ in 0..55 {
x112 = x112.sqr();
}
x112 *= &x56;
let mut x126 = x112.sqr();
for _ in 0..13 {
x126 = x126.sqr();
}
x126 *= &x14;
let mut t = x126;
for _ in 0..3 {
t = t.sqr();
}
t *= &u5;
for _ in 0..4 {
t = t.sqr();
}
t *= &x3;
for _ in 0..4 {
t = t.sqr();
}
t *= &u5;
for _ in 0..5 {
t = t.sqr();
}
t *= &u11;
for _ in 0..4 {
t = t.sqr();
}
t *= &u11;
for _ in 0..4 {
t = t.sqr();
}
t *= &x3;
for _ in 0..5 {
t = t.sqr();
}
t *= &x3;
for _ in 0..6 {
t = t.sqr();
}
t *= &u13;
for _ in 0..4 {
t = t.sqr();
}
t *= &u5;
for _ in 0..3 {
t = t.sqr();
}
t *= &x3;
for _ in 0..5 {
t = t.sqr();
}
t *= &u9;
for _ in 0..6 {
t = t.sqr();
}
t *= &u5;
for _ in 0..10 {
t = t.sqr();
}
t *= &x3;
for _ in 0..4 {
t = t.sqr();
}
t *= &x3;
for _ in 0..9 {
t = t.sqr();
}
t *= &x8;
for _ in 0..5 {
t = t.sqr();
}
t *= &u9;
for _ in 0..6 {
t = t.sqr();
}
t *= &u11;
for _ in 0..4 {
t = t.sqr();
}
t *= &u13;
for _ in 0..5 {
t = t.sqr();
}
t *= &x2;
for _ in 0..6 {
t = t.sqr();
}
t *= &u13;
for _ in 0..10 {
t = t.sqr();
}
t *= &u13;
for _ in 0..4 {
t = t.sqr();
}
t *= &u9;
for _ in 0..6 {
t = t.sqr();
}
t *= x;
for _ in 0..8 {
t = t.sqr();
}
*self = t * x6;
}
pub fn inv(&self) -> Scalar {
let mut ret = Scalar::default();
ret.inv_in_place(self);
ret
}
pub fn inv_var(&self) -> Scalar {
self.inv()
}
pub fn is_even(&self) -> bool {
self.0[0] & 1 == 0
}
}
impl Default for Scalar {
fn default() -> Scalar {
Scalar([0u32; 8])
}
}
impl Add<Scalar> for Scalar {
type Output = Scalar;
fn add(mut self, other: Scalar) -> Scalar {
self.add_assign(&other);
self
}
}
impl<'a, 'b> Add<&'a Scalar> for &'b Scalar {
type Output = Scalar;
fn add(self, other: &'a Scalar) -> Scalar {
let mut ret = *self;
ret.add_assign(other);
ret
}
}
impl<'a> AddAssign<&'a Scalar> for Scalar {
fn add_assign(&mut self, other: &'a Scalar) {
let mut t = 0u64;
unroll! {
for i in 0..8 {
t += (self.0[i] as u64) + (other.0[i] as u64);
self.0[i] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
}
}
let overflow = self.check_overflow();
self.reduce(Choice::from(t as u8) | overflow);
}
}
impl AddAssign<Scalar> for Scalar {
fn add_assign(&mut self, other: Scalar) {
self.add_assign(&other)
}
}
impl Mul<Scalar> for Scalar {
type Output = Scalar;
fn mul(self, other: Scalar) -> Scalar {
let mut ret = Scalar::default();
ret.mul_in_place(&self, &other);
ret
}
}
impl<'a, 'b> Mul<&'a Scalar> for &'b Scalar {
type Output = Scalar;
fn mul(self, other: &'a Scalar) -> Scalar {
let mut ret = Scalar::default();
ret.mul_in_place(self, other);
ret
}
}
impl<'a> MulAssign<&'a Scalar> for Scalar {
fn mul_assign(&mut self, other: &'a Scalar) {
let mut ret = Scalar::default();
ret.mul_in_place(self, other);
*self = ret;
}
}
impl MulAssign<Scalar> for Scalar {
fn mul_assign(&mut self, other: Scalar) {
self.mul_assign(&other)
}
}
impl Neg for Scalar {
type Output = Scalar;
fn neg(mut self) -> Scalar {
self.cond_neg_assign(1.into());
self
}
}
impl<'a> Neg for &'a Scalar {
type Output = Scalar;
fn neg(self) -> Scalar {
let value = *self;
-value
}
}
impl core::fmt::LowerHex for Scalar {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for word in &self.0[..] {
for byte in word.to_be_bytes().iter() {
write!(f, "{:02x}", byte)?;
}
}
Ok(())
}
}