#![allow(non_snake_case)]
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use super::field::{GFp256, ModInt256};
use sha2::{Sha256, Sha512, Digest};
use super::{CryptoRng, RngCore};
#[cfg(feature = "alloc")]
use crate::Vec;
#[derive(Clone, Copy, Debug)]
pub struct Point {
X: GFp256,
Y: GFp256,
Z: GFp256,
}
pub type Scalar = ModInt256<0xF3B9CAC2FC632551, 0xBCE6FAADA7179E84,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFF00000000>;
impl Scalar {
pub fn encode(self) -> [u8; 32] {
self.encode32()
}
}
fn bswap32(x: &[u8]) -> [u8; 32] {
let mut y = [0u8; 32];
for i in 0..32 {
y[i] = x[31 - i];
}
y
}
impl Point {
pub const NEUTRAL: Self = Self {
X: GFp256::ZERO,
Y: GFp256::ONE,
Z: GFp256::ZERO,
};
pub const BASE: Self = Self {
X: GFp256::w64be(
0x6B17D1F2E12C4247, 0xF8BCE6E563A440F2,
0x77037D812DEB33A0, 0xF4A13945D898C296),
Y: GFp256::w64be(
0x4FE342E2FE1A7F9B, 0x8EE7EB4A7C0F9E16,
0x2BCE33576B315ECE, 0xCBB6406837BF51F5),
Z: GFp256::ONE,
};
const B: GFp256 = GFp256::w64be(
0x5AC635D8AA3A93E7,
0xB3EBBD55769886BC,
0x651D06B0CC53B0F6,
0x3BCE3C3E27D2604B,
);
const B2: GFp256 = GFp256::w64be(
0xB58C6BB1547527CF,
0x67D77AAAED310D78,
0xCA3A0D6198A761EC,
0x779C787C4FA4C096,
);
const B4: GFp256 = GFp256::w64be(
0x6B18D763A8EA4F9D,
0xCFAEF555DA621AF1,
0x94741AC2314EC3D8,
0xEF38F0F89F49812D,
);
const B8: GFp256 = GFp256::w64be(
0xD631AEC751D49F3B,
0x9F5DEAABB4C435E3,
0x28E83584629D87B1,
0xDE71E1F13E93025A,
);
const THREE: GFp256 = GFp256::w64be(
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
0x0000000000000003,
);
pub fn set_decode(&mut self, buf: &[u8]) -> u32 {
*self = Self::NEUTRAL;
if buf.len() == 1 {
return (((buf[0] as i32) - 1) >> 8) as u32;
} else if buf.len() == 33 {
let mut r = (((((buf[0] & 0xFE) ^ 0x02) as i32) - 1) >> 8) as u32;
let (x, rx) = GFp256::decode32(&bswap32(&buf[1..33]));
r &= rx;
let (mut y, ry) = (x * (x.square() - Self::THREE) + Self::B).sqrt();
r &= ry;
let yb = y.encode()[0];
let ws = (((yb ^ buf[0]) & 0x01) as u32).wrapping_neg();
y.set_cond(&-y, ws);
self.X = GFp256::select(&GFp256::ZERO, &x, r);
self.Y = GFp256::select(&GFp256::ONE, &y, r);
self.Z = GFp256::select(&GFp256::ZERO, &GFp256::ONE, r);
return r;
} else if buf.len() == 65 {
let mut r = ((((buf[0] ^ 0x04) as i32) - 1) >> 8) as u32;
let (x, rx) = GFp256::decode32(&bswap32(&buf[1..33]));
let (y, ry) = GFp256::decode32(&bswap32(&buf[33..65]));
r &= rx & ry;
r &= y.square().equals(x * (x.square() - Self::THREE) + Self::B);
self.X = GFp256::select(&GFp256::ZERO, &x, r);
self.Y = GFp256::select(&GFp256::ONE, &y, r);
self.Z = GFp256::select(&GFp256::ZERO, &GFp256::ONE, r);
return r;
} else {
return 0;
}
}
pub fn decode(buf: &[u8]) -> Option<Point> {
let mut P = Point::NEUTRAL;
if P.set_decode(buf) != 0 {
Some(P)
} else {
None
}
}
pub fn encode_compressed(self) -> [u8; 33] {
let r = !self.isneutral();
let iZ = GFp256::ONE / self.Z; let x = self.X * iZ; let y = self.Y * iZ; let mut b = [0u8; 33];
b[0] = ((y.encode()[0] & 0x01) | 0x02) & (r as u8);
b[1..33].copy_from_slice(&bswap32(&x.encode()));
b
}
pub fn encode_uncompressed(self) -> [u8; 65] {
let r = !self.isneutral();
let iZ = GFp256::ONE / self.Z; let x = self.X * iZ; let y = self.Y * iZ; let mut b = [0u8; 65];
b[0] = 0x04 & (r as u8);
b[ 1..33].copy_from_slice(&bswap32(&x.encode()));
b[33..65].copy_from_slice(&bswap32(&y.encode()));
b
}
pub fn to_affine(self) -> (GFp256, GFp256, u32) {
let mut bb = self.encode_uncompressed();
let r = (((bb[0] as i32) - 1) >> 8) as u32;
bb[32] |= (r & 1) as u8;
let (x, _) = GFp256::decode32(&bswap32(&bb[1..33]));
let (y, _) = GFp256::decode32(&bswap32(&bb[33..65]));
(x, y, r)
}
pub fn to_projective(self) -> (GFp256, GFp256, GFp256) {
(self.X, self.Y, self.Z)
}
pub fn set_affine(&mut self, x: GFp256, y: GFp256) -> u32 {
*self = Self::NEUTRAL;
let y2 = x * (x.square() - Self::THREE) + Self::B;
let r = y.square().equals(y2);
self.X.set_cond(&x, r);
self.Y.set_cond(&y, r);
self.Z.set_cond(&GFp256::ONE, r);
r
}
pub fn from_affine(x: GFp256, y: GFp256) -> Option<Self> {
let mut P = Self::NEUTRAL;
if P.set_affine(x, y) != 0 {
Some(P)
} else {
None
}
}
pub fn set_projective(&mut self, X: GFp256, Y: GFp256, Z: GFp256) -> u32 {
*self = Self::NEUTRAL;
let zn = Z.iszero();
let Z2 = Z.square();
let Y2 = X * X.square() + Z2 * (Self::B * Z - X.mul3());
let r = (Y.square() * Z).equals(Y2) & !zn;
self.X.set_cond(&X, r);
self.Y.set_cond(&Y, r);
self.Z.set_cond(&Z, r);
r | zn
}
pub fn from_projective(X: GFp256, Y: GFp256, Z: GFp256) -> Option<Self> {
let mut P = Self::NEUTRAL;
if P.set_projective(X, Y, Z) != 0 {
Some(P)
} else {
None
}
}
fn set_add(&mut self, rhs: &Self) {
let (X1, Y1, Z1) = (&self.X, &self.Y, &self.Z);
let (X2, Y2, Z2) = (&rhs.X, &rhs.Y, &rhs.Z);
let x1x2 = X1 * X2;
let y1y2 = Y1 * Y2;
let z1z2 = Z1 * Z2;
let C = (X1 + Y1) * (X2 + Y2) - x1x2 - y1y2; let D = (Y1 + Z1) * (Y2 + Z2) - y1y2 - z1z2; let E = (X1 + Z1) * (X2 + Z2) - x1x2 - z1z2; let F = (E - Self::B * z1z2).mul3();
let G = y1y2 - F;
let H = y1y2 + F;
let I = z1z2.mul3();
let J = (Self::B * E - x1x2 - I).mul3();
let K = x1x2.mul3() - I;
let L = D * J;
let M = K * J;
let N = K * C;
let Y3 = H * G + M;
let X3 = H * C - L;
let Z3 = G * D + N;
self.X = X3;
self.Y = Y3;
self.Z = Z3;
}
fn set_add_affine(&mut self, rhs: &PointAffine, rz: u32) {
let (X1, Y1, Z1) = (&self.X, &self.Y, &self.Z);
let (X2, Y2) = (&rhs.x, &rhs.y);
let x1x2 = X1 * X2;
let y1y2 = Y1 * Y2;
let C = (X1 + Y1) * (X2 + Y2) - x1x2 - y1y2; let D = Y2 * Z1 + Y1; let E = X2 * Z1 + X1; let F = (E - Self::B * Z1).mul3();
let G = y1y2 - F;
let H = y1y2 + F;
let I = Z1.mul3();
let J = (Self::B * E - x1x2 - I).mul3();
let K = x1x2.mul3() - I;
let L = D * J;
let M = K * J;
let N = K * C;
let Y3 = H * G + M;
let X3 = H * C - L;
let Z3 = G * D + N;
self.X.set_cond(&X3, !rz);
self.Y.set_cond(&Y3, !rz);
self.Z.set_cond(&Z3, !rz);
}
fn set_sub_affine(&mut self, rhs: &PointAffine, rz: u32) {
self.set_add_affine(&PointAffine { x: rhs.x, y: -rhs.y }, rz);
}
pub fn set_double(&mut self) {
let (X, Y, Z) = (&self.X, &self.Y, &self.Z);
let zn = Z.iszero();
let s = (Y * Z).mul2();
let w = ((X - Z) * (X + Z)).mul3();
let R = Y * s;
let ss = s.square();
let RR = R.square();
let B = (X * R).mul2();
let h = w.square() - B - B;
let Z3 = s * ss;
let X3 = s * h;
let Y3 = w * (B - h) - RR.mul2();
self.X = X3;
self.Y = GFp256::select(&Y3, &GFp256::ONE, zn);
self.Z = Z3;
}
#[inline(always)]
pub fn double(self) -> Self {
let mut r = self;
r.set_double();
r
}
pub fn set_xdouble(&mut self, n: u32) {
if n == 0 {
return;
}
if n == 1 {
self.set_double();
return;
}
let (X, Y, Z) = (&self.X, &self.Y, &self.Z);
let s = (Y * Z).mul2();
let w = ((X - Z) * (X + Z)).mul3();
let R = Y * s;
let RR = R.square();
let B = (X * R).mul2();
let mut X = w.square() - B - B;
let mut Y = w * (B - X) - RR.mul2();
let mut Z = s;
for _ in 1..n {
let Z2 = Z.square();
let A = ((X - Z2) * (X + Z2)).mul3();
let B = Y.mul2();
Z *= B;
let C = B.square();
let D = C.square().half();
let E = C * X;
X = A.square() - E.mul2();
Y = (E - X) * A - D;
}
self.X = X * Z;
self.Y = GFp256::select(&Y, &GFp256::ONE, Z.iszero());
self.Z = Z * Z.square();
}
#[inline(always)]
pub fn xdouble(self, n: u32) -> Self {
let mut r = self;
r.set_xdouble(n);
r
}
#[inline(always)]
pub fn set_neg(&mut self) {
self.Y.set_neg();
}
fn set_sub(&mut self, rhs: &Self) {
self.set_add(&-rhs);
}
pub fn set_mul_small(&mut self, n: u64) {
if n == 0 {
*self = Self::NEUTRAL;
return;
}
if n == 1 {
return;
}
let nlen = 64 - n.leading_zeros();
let T = *self;
let mut ndbl = 0u32;
for i in (0..(nlen - 1)).rev() {
ndbl += 1;
if ((n >> i) & 1) == 0 {
continue;
}
self.set_xdouble(ndbl);
ndbl = 0;
self.set_add(&T);
}
self.set_xdouble(ndbl);
}
#[inline]
pub fn equals(self, rhs: Self) -> u32 {
(self.X * rhs.Z).equals(rhs.X * self.Z)
& (self.Y * rhs.Z).equals(rhs.Y * self.Z)
}
#[inline(always)]
pub fn isneutral(self) -> u32 {
self.Z.iszero()
}
#[inline]
pub fn set_cond(&mut self, P: &Self, ctl: u32) {
self.X.set_cond(&P.X, ctl);
self.Y.set_cond(&P.Y, ctl);
self.Z.set_cond(&P.Z, ctl);
}
#[inline(always)]
pub fn select(P0: &Self, P1: &Self, ctl: u32) -> Self {
let mut P = *P0;
P.set_cond(P1, ctl);
P
}
#[inline]
pub fn set_condneg(&mut self, ctl: u32) {
self.Y.set_cond(&-self.Y, ctl);
}
fn recode_scalar(n: &Scalar) -> [i8; 52] {
let mut sd = [0i8; 52];
let bb = n.encode();
let mut cc: u32 = 0; let mut i: usize = 0; let mut acc: u32 = 0; let mut acc_len: i32 = 0; for j in 0..52 {
if acc_len < 5 && j < 51 {
acc |= (bb[i] as u32) << acc_len;
acc_len += 8;
i += 1;
}
let d = (acc & 0x1F) + cc;
acc >>= 5;
acc_len -= 5;
let m = 16u32.wrapping_sub(d) >> 8;
sd[j] = (d.wrapping_sub(m & 32)) as i8;
cc = m & 1;
}
sd
}
fn lookup(win: &[Self; 16], k: i8) -> Self {
let s = ((k as i32) >> 8) as u32;
let f = ((k as u32) ^ s).wrapping_sub(s);
let mut P = Self::NEUTRAL;
for i in 0..16 {
let j = (i as u32) + 1;
let w = !(f.wrapping_sub(j) | j.wrapping_sub(f));
let w = ((w as i32) >> 31) as u32;
P.X.set_cond(&win[i].X, w);
P.Y.set_cond(&win[i].Y, w);
P.Z.set_cond(&win[i].Z, w);
}
P.Y.set_cond(&-P.Y, s);
P
}
pub fn set_mul(&mut self, n: &Scalar) {
let mut win = [Self::NEUTRAL; 16];
win[0] = *self;
for i in 1..8 {
let j = 2 * i;
win[j - 1] = win[i - 1].double();
win[j] = win[j - 1] + win[0];
}
win[15] = win[7].double();
let sd = Self::recode_scalar(n);
*self = Self::lookup(&win, sd[51]);
for i in (0..51).rev() {
self.set_xdouble(5);
self.set_add(&Self::lookup(&win, sd[i]));
}
}
fn lookup_affine(win: &[PointAffine; 16], k: i8) -> (PointAffine, u32) {
let s = ((k as i32) >> 8) as u32;
let f = ((k as u32) ^ s).wrapping_sub(s);
let mut P = PointAffine { x: GFp256::ZERO, y: GFp256::ONE };
for i in 0..16 {
let j = (i as u32) + 1;
let w = !(f.wrapping_sub(j) | j.wrapping_sub(f));
let w = ((w as i32) >> 31) as u32;
P.x.set_cond(&win[i].x, w);
P.y.set_cond(&win[i].y, w);
}
P.y.set_cond(&-P.y, s);
let fz = (((f as i32) - 1) >> 8) as u32;
(P, fz)
}
#[inline]
fn lookup_affine_proj(win: &[PointAffine; 16], k: i8) -> Self {
let (P, rz) = Self::lookup_affine(win, k);
Self {
X: P.x,
Y: P.y,
Z: GFp256::select(&GFp256::ONE, &GFp256::ZERO, rz),
}
}
#[inline]
fn set_lookup_affine_add(&mut self, win: &[PointAffine; 16], k: i8) {
let (P, rz) = Self::lookup_affine(win, k);
self.set_add_affine(&P, rz);
}
pub fn set_mulgen(&mut self, n: &Scalar) {
let sd = Self::recode_scalar(n);
*self = Self::lookup_affine_proj(&PRECOMP_G, sd[12]);
self.set_lookup_affine_add(&PRECOMP_G65, sd[25]);
self.set_lookup_affine_add(&PRECOMP_G130, sd[38]);
self.set_lookup_affine_add(&PRECOMP_G195, sd[51]);
for i in (0..12).rev() {
self.set_xdouble(5);
self.set_lookup_affine_add(&PRECOMP_G, sd[i]);
self.set_lookup_affine_add(&PRECOMP_G65, sd[i + 13]);
self.set_lookup_affine_add(&PRECOMP_G130, sd[i + 26]);
self.set_lookup_affine_add(&PRECOMP_G195, sd[i + 39]);
}
}
#[inline]
pub fn mulgen(n: &Scalar) -> Self {
let mut P = Self::NEUTRAL;
P.set_mulgen(n);
P
}
fn recode_scalar_NAF(n: &Scalar) -> [i8; 257] {
let mut sd = [0i8; 257];
let bb = n.encode();
let mut x = bb[0] as u32;
for i in 0..257 {
if (i & 7) == 4 && i < 252 {
x += (bb[(i + 4) >> 3] as u32) << 4;
}
let m = (x & 1).wrapping_neg(); let v = x & m & 31; let c = (v & 16) << 1; let d = v.wrapping_sub(c); sd[i] = d as i8;
x = x.wrapping_sub(d) >> 1;
}
sd
}
fn recode_u129_NAF(nh: u32, nl: u128) -> [i8; 130] {
let mut sd = [0i8; 130];
let mut y = nl;
let x = y as u32;
let m = (x & 1).wrapping_neg(); let v = x & m & 31; let c = (v & 16) << 1; sd[0] = v.wrapping_sub(c) as i8;
y = (y.wrapping_sub(v as u128) >> 1).wrapping_add((nh as u128) << 127);
y = y.wrapping_add((c >> 1) as u128);
for i in 1..130 {
let x = y as u32;
let m = (x & 1).wrapping_neg(); let v = x & m & 31; let c = (v & 16) << 1; sd[i] = v.wrapping_sub(c) as i8;
y = y.wrapping_sub(v as u128).wrapping_add(c as u128) >> 1;
}
sd
}
pub fn set_mul_add_mulgen_vartime(&mut self, u: &Scalar, v: &Scalar) {
let sdu = Self::recode_scalar_NAF(&u);
let sdv = Self::recode_scalar_NAF(&v);
let mut win = [Self::NEUTRAL; 8];
let Q = self.double();
win[0] = *self;
for i in 1..8 {
win[i] = win[i - 1] + Q;
}
let mut zz = true;
let mut ndbl = 0u32;
for i in (0..257).rev() {
ndbl += 1;
let e1 = sdu[i];
let e2 = sdv[i];
if ((e1 as u32) | (e2 as u32)) == 0 {
continue;
}
if zz {
*self = Self::NEUTRAL;
zz = false;
} else {
self.set_xdouble(ndbl);
}
ndbl = 0u32;
if e1 != 0 {
if e1 > 0 {
self.set_add(&win[e1 as usize >> 1]);
} else {
self.set_sub(&win[(-e1) as usize >> 1]);
}
}
if e2 != 0 {
if e2 > 0 {
self.set_add_affine(&PRECOMP_G[e2 as usize - 1], 0);
} else {
self.set_sub_affine(&PRECOMP_G[(-e2) as usize - 1], 0);
}
}
}
if zz {
*self = Self::NEUTRAL;
} else {
if ndbl > 0 {
self.set_xdouble(ndbl);
}
}
}
#[inline(always)]
pub fn mul_add_mulgen_vartime(self, u: &Scalar, v: &Scalar) -> Self {
let mut R = self;
R.set_mul_add_mulgen_vartime(u, v);
R
}
pub fn verify_helper_vartime(self,
R: &Point, s: &Scalar, k: &Scalar) -> bool
{
const T128: Scalar = Scalar::w64be(0, 1, 0, 0);
const INV_T128: Scalar = Scalar::w64be(
0x48C9440834AB8EDC, 0x982639CE9EA3C688,
0xCBBD4262B843B209, 0x3CB8EB5DA1D57E2A);
let (c0, c1) = k.split_vartime();
let kr = (k * Scalar::from_i128(c1) - Scalar::from_i128(c0)) * INV_T128;
let mut a = -1i32;
let mut va = Scalar::MINUS_ONE;
let mut b = -100i32;
for _ in 0..3 {
if (va - k).equals(kr) != 0 {
b = 1;
break;
}
if va.equals(kr) != 0 {
b = 0;
break;
}
if (va + k).equals(kr) != 0 {
b = -1;
break;
}
a += 1;
va += Scalar::ONE;
}
assert!(b != -100);
let c0h = (a as u32).wrapping_add((c0 >> 127) as u32);
let c0l = c0 as u128;
let c1h = (b as u32).wrapping_add((c1 >> 127) as u32);
let c1l = c1 as u128;
let (P1, d1h, d1l) = if (c1h >> 31) != 0 {
(*R, !c1h.wrapping_add((c1l == 0) as u32), c1l.wrapping_neg())
} else {
(-R, c1h, c1l)
};
let (P2, d2h, d2l) = if (c0h >> 31) != 0 {
(self, !c0h.wrapping_add((c0l == 0) as u32), c0l.wrapping_neg())
} else {
(-self, c0h, c0l)
};
let ss = s * (T128 * Scalar::from_i32(c1h as i32)
+ Scalar::from_u128(c1l));
let sd1 = Self::recode_u129_NAF(d1h, d1l);
let sd2 = Self::recode_u129_NAF(d2h, d2l);
let sd3 = Self::recode_scalar_NAF(&ss);
let Q1 = P1.double();
let Q2 = P2.double();
let mut win1 = [Self::NEUTRAL; 8];
let mut win2 = [Self::NEUTRAL; 8];
win1[0] = P1;
win2[0] = P2;
for i in 1..8 {
win1[i] = win1[i - 1] + Q1;
win2[i] = win2[i - 1] + Q2;
}
let mut T = Self::NEUTRAL;
let mut zz = true;
let mut ndbl = 0u32;
for i in (0..130).rev() {
ndbl += 1;
let e1 = sd1[i];
let e2 = sd2[i];
let e3 = sd3[i];
let e4 = if i < 127 { sd3[i + 130] } else { 0 };
if ((e1 as u32) | (e2 as u32) | (e3 as u32) | (e4 as u32)) == 0 {
continue;
}
if zz {
zz = false;
} else {
T.set_xdouble(ndbl);
}
ndbl = 0u32;
if e1 != 0 {
if e1 > 0 {
T.set_add(&win1[e1 as usize >> 1]);
} else {
T.set_sub(&win1[(-e1) as usize >> 1]);
}
}
if e2 != 0 {
if e2 > 0 {
T.set_add(&win2[e2 as usize >> 1]);
} else {
T.set_sub(&win2[(-e2) as usize >> 1]);
}
}
if e3 != 0 {
if e3 > 0 {
T.set_add_affine(&PRECOMP_G[e3 as usize - 1], 0);
} else {
T.set_sub_affine(&PRECOMP_G[(-e3) as usize - 1], 0);
}
}
if e4 != 0 {
if e4 > 0 {
T.set_add_affine(&PRECOMP_G130[e4 as usize - 1], 0);
} else {
T.set_sub_affine(&PRECOMP_G130[(-e4) as usize - 1], 0);
}
}
}
T.isneutral() != 0
}
pub fn to_x_affine_diff(P0: Self, P1: Self) -> (GFp256, GFp256, GFp256) {
let Q = P1 - P0;
let mut x0 = P0.X;
let mut z0 = P0.Z;
x0.set_cond(&GFp256::ONE, P0.isneutral());
z0.set_cond(&GFp256::ONE, P0.isneutral());
let mut x1 = P1.X;
let mut z1 = P1.Z;
x1.set_cond(&GFp256::ONE, P1.isneutral());
z1.set_cond(&GFp256::ONE, P1.isneutral());
let mut xq = Q.X;
let mut zq = Q.Z;
xq.set_cond(&GFp256::ONE, Q.isneutral());
zq.set_cond(&GFp256::ONE, Q.isneutral());
let z0z1 = z0 * z1;
let mut k = GFp256::ONE / (z0z1 * zq);
xq *= k * z0z1;
k *= zq;
x1 *= k * z0;
k *= z1;
x0 *= k;
(x0, x1, xq)
}
pub fn x_sequence_vartime(x0: GFp256, x1: GFp256, xq: GFp256,
xx: &mut [GFp256]) -> (GFp256, GFp256)
{
fn xadd(X0: GFp256, Z0: GFp256, X1: GFp256, Z1: GFp256, xq: GFp256)
-> (GFp256, GFp256)
{
let C = xq * Z1; let D = X1 * xq; let E = (X1 + C) * Z1; let F = (D + Z1.mul3()).square(); let G = E * Point::B4; let H = (X1 - C).square(); let X2 = Z0 * (F - G);
let Z2 = X0 * H;
(X2, Z2)
}
fn xadd_spec(X1: GFp256, Z1: GFp256, xq: GFp256)
-> (GFp256, GFp256)
{
let C = X1 * xq;
let D = xq * Z1;
let E = Z1.square();
let F = (C - Z1.mul3()) * (X1 + D);
let G = E * Point::B2;
let Z2 = (X1 - D).square();
let X2 = (F + G).mul2();
(X2, Z2)
}
let n = xx.len();
if n == 0 {
return (x0, x1);
}
if xq.equals(GFp256::ONE) != 0 {
for i in 0..n {
xx[i] = x0;
}
return (x0, x0);
}
let mut X0 = x0;
let mut Z0 = if x0.equals(GFp256::ONE) != 0 {
GFp256::ZERO
} else {
GFp256::ONE
};
let mut X1 = x1;
let mut Z1 = if x1.equals(GFp256::ONE) != 0 {
GFp256::ZERO
} else {
GFp256::ONE
};
let mut i = 0;
loop {
let blen = if (n - i) < 198 { n - i } else { 198 };
let mut XX = [GFp256::ZERO; 200];
let mut ZZ = [GFp256::ZERO; 200];
for j in 0..blen {
XX[j] = X0;
ZZ[j] = Z0;
let (X2, Z2) = if Z0.iszero() != 0 {
let xqxq = xq.square();
let Xt = (xqxq + Self::THREE).square() - xq * Self::B8;
let Zt = ((xqxq - Self::THREE) * xq + Self::B).mul4();
(Xt, Zt)
} else if Z1.iszero() != 0 {
(xq, GFp256::ONE)
} else if X0.iszero() != 0 {
xadd_spec(X1, Z1, xq)
} else {
xadd(X0, Z0, X1, Z1, xq)
};
(X0, Z0) = (X1, Z1);
(X1, Z1) = (X2, Z2);
}
let ilen = if (i + blen) == n {
XX[blen] = X0;
ZZ[blen] = Z0;
XX[blen + 1] = X1;
ZZ[blen + 1] = Z1;
blen + 2
} else {
blen
};
GFp256::batch_invert(&mut ZZ[0..ilen]);
for j in 0..ilen {
let iZ = ZZ[j];
let mut x = XX[j] * iZ;
if iZ.iszero() != 0 {
x = GFp256::ONE;
}
if j < blen {
xx[i + j] = x;
} else {
XX[j] = x;
}
}
i += blen;
if i == n {
return (XX[blen], XX[blen + 1]);
}
}
}
}
impl Add<Point> for Point {
type Output = Point;
#[inline(always)]
fn add(self, other: Point) -> Point {
let mut r = self;
r.set_add(&other);
r
}
}
impl Add<&Point> for Point {
type Output = Point;
#[inline(always)]
fn add(self, other: &Point) -> Point {
let mut r = self;
r.set_add(other);
r
}
}
impl Add<Point> for &Point {
type Output = Point;
#[inline(always)]
fn add(self, other: Point) -> Point {
let mut r = *self;
r.set_add(&other);
r
}
}
impl Add<&Point> for &Point {
type Output = Point;
#[inline(always)]
fn add(self, other: &Point) -> Point {
let mut r = *self;
r.set_add(other);
r
}
}
impl AddAssign<Point> for Point {
#[inline(always)]
fn add_assign(&mut self, other: Point) {
self.set_add(&other);
}
}
impl AddAssign<&Point> for Point {
#[inline(always)]
fn add_assign(&mut self, other: &Point) {
self.set_add(other);
}
}
impl Mul<Scalar> for Point {
type Output = Point;
#[inline(always)]
fn mul(self, other: Scalar) -> Point {
let mut r = self;
r.set_mul(&other);
r
}
}
impl Mul<&Scalar> for Point {
type Output = Point;
#[inline(always)]
fn mul(self, other: &Scalar) -> Point {
let mut r = self;
r.set_mul(other);
r
}
}
impl Mul<Scalar> for &Point {
type Output = Point;
#[inline(always)]
fn mul(self, other: Scalar) -> Point {
let mut r = *self;
r.set_mul(&other);
r
}
}
impl Mul<&Scalar> for &Point {
type Output = Point;
#[inline(always)]
fn mul(self, other: &Scalar) -> Point {
let mut r = *self;
r.set_mul(other);
r
}
}
impl MulAssign<Scalar> for Point {
#[inline(always)]
fn mul_assign(&mut self, other: Scalar) {
self.set_mul(&other);
}
}
impl MulAssign<&Scalar> for Point {
#[inline(always)]
fn mul_assign(&mut self, other: &Scalar) {
self.set_mul(other);
}
}
impl Mul<Point> for Scalar {
type Output = Point;
#[inline(always)]
fn mul(self, other: Point) -> Point {
let mut r = other;
r.set_mul(&self);
r
}
}
impl Mul<&Point> for Scalar {
type Output = Point;
#[inline(always)]
fn mul(self, other: &Point) -> Point {
let mut r = *other;
r.set_mul(&self);
r
}
}
impl Mul<Point> for &Scalar {
type Output = Point;
#[inline(always)]
fn mul(self, other: Point) -> Point {
let mut r = other;
r.set_mul(self);
r
}
}
impl Mul<&Point> for &Scalar {
type Output = Point;
#[inline(always)]
fn mul(self, other: &Point) -> Point {
let mut r = *other;
r.set_mul(self);
r
}
}
impl Mul<u64> for Point {
type Output = Point;
#[inline(always)]
fn mul(self, other: u64) -> Point {
let mut r = self;
r.set_mul_small(other);
r
}
}
impl Mul<u64> for &Point {
type Output = Point;
#[inline(always)]
fn mul(self, other: u64) -> Point {
let mut r = *self;
r.set_mul_small(other);
r
}
}
impl MulAssign<u64> for Point {
#[inline(always)]
fn mul_assign(&mut self, other: u64) {
self.set_mul_small(other);
}
}
impl Mul<Point> for u64 {
type Output = Point;
#[inline(always)]
fn mul(self, other: Point) -> Point {
let mut r = other;
r.set_mul_small(self);
r
}
}
impl Mul<&Point> for u64 {
type Output = Point;
#[inline(always)]
fn mul(self, other: &Point) -> Point {
let mut r = *other;
r.set_mul_small(self);
r
}
}
impl Neg for Point {
type Output = Point;
#[inline(always)]
fn neg(self) -> Point {
let mut r = self;
r.set_neg();
r
}
}
impl Neg for &Point {
type Output = Point;
#[inline(always)]
fn neg(self) -> Point {
let mut r = *self;
r.set_neg();
r
}
}
impl Sub<Point> for Point {
type Output = Point;
#[inline(always)]
fn sub(self, other: Point) -> Point {
let mut r = self;
r.set_sub(&other);
r
}
}
impl Sub<&Point> for Point {
type Output = Point;
#[inline(always)]
fn sub(self, other: &Point) -> Point {
let mut r = self;
r.set_sub(other);
r
}
}
impl Sub<Point> for &Point {
type Output = Point;
#[inline(always)]
fn sub(self, other: Point) -> Point {
let mut r = *self;
r.set_sub(&other);
r
}
}
impl Sub<&Point> for &Point {
type Output = Point;
#[inline(always)]
fn sub(self, other: &Point) -> Point {
let mut r = *self;
r.set_sub(other);
r
}
}
impl SubAssign<Point> for Point {
#[inline(always)]
fn sub_assign(&mut self, other: Point) {
self.set_sub(&other);
}
}
impl SubAssign<&Point> for Point {
#[inline(always)]
fn sub_assign(&mut self, other: &Point) {
self.set_sub(other);
}
}
#[derive(Clone, Copy, Debug)]
pub struct PrivateKey {
x: Scalar, }
#[derive(Clone, Copy, Debug)]
pub struct PublicKey {
pub point: Point,
}
impl PrivateKey {
pub fn generate<T: CryptoRng + RngCore>(rng: &mut T) -> Self {
let mut seed = [0u8; 32];
rng.fill_bytes(&mut seed);
Self::from_seed(&seed)
}
pub fn decode(buf: &[u8]) -> Option<Self> {
if buf.len() != 32 {
return None;
}
let (x, r) = Scalar::decode32(&bswap32(buf));
if (r & !x.iszero()) != 0 {
Some(Self { x })
} else {
None
}
}
pub fn encode(self) -> [u8; 32] {
let buf = self.x.encode();
bswap32(&buf)
}
pub fn from_seed(seed: &[u8]) -> Self {
let mut sh = Sha512::new();
sh.update(&[ 0x63, 0x72, 0x72, 0x6c, 0x20,
0x50, 0x2d, 0x32, 0x35, 0x36 ]);
sh.update(seed);
let mut x = Scalar::decode_reduce(&sh.finalize()[..]);
x.set_cond(&Scalar::ONE, x.iszero());
Self { x }
}
pub fn to_public_key(self) -> PublicKey {
PublicKey { point: Point::mulgen(&self.x) }
}
pub fn sign_hash(self, hv: &[u8], extra_rand: &[u8]) -> [u8; 64] {
fn hmac_start(sh: &mut Sha256, key: &[u8; 32]) {
let mut tmp = [0x36u8; 64];
for i in 0..32 {
tmp[i] ^= key[i];
}
sh.update(&tmp);
}
fn hmac_end(sh: &mut Sha256, key: &[u8; 32]) -> [u8; 32] {
let v = sh.finalize_reset();
let mut tmp = [0x5Cu8; 64];
for i in 0..32 {
tmp[i] ^= key[i];
}
sh.update(&tmp);
sh.update(&v);
sh.finalize_reset().into()
}
let mut tmp = [0u8; 32];
if hv.len() >= 32 {
tmp[..].copy_from_slice(&hv[..32]);
} else {
tmp[(32 - hv.len())..32].copy_from_slice(hv);
}
let h = Scalar::decode_reduce(&bswap32(&tmp));
let hb = bswap32(&h.encode());
let xb = bswap32(&self.x.encode());
let mut sh = Sha256::new();
let V = [0x01u8; 32];
let K = [0x00u8; 32];
hmac_start(&mut sh, &K);
sh.update(&V);
sh.update(&[0x00u8]);
sh.update(&xb);
sh.update(&hb);
if extra_rand.len() > 0 {
sh.update(&extra_rand);
}
let K = hmac_end(&mut sh, &K);
hmac_start(&mut sh, &K);
sh.update(&V);
let V = hmac_end(&mut sh, &K);
hmac_start(&mut sh, &K);
sh.update(&V);
sh.update(&[0x01u8]);
sh.update(&xb);
sh.update(&hb);
if extra_rand.len() > 0 {
sh.update(&extra_rand);
}
let mut K = hmac_end(&mut sh, &K);
hmac_start(&mut sh, &K);
sh.update(&V);
let mut V = hmac_end(&mut sh, &K);
loop {
hmac_start(&mut sh, &K);
sh.update(&V);
V[..].copy_from_slice(&hmac_end(&mut sh, &K));
let (k, cc) = Scalar::decode32(&bswap32(&V));
if cc != 0 && k.iszero() == 0 {
let R = Point::mulgen(&k);
let xR_le = bswap32(&R.encode_compressed()[1..33]);
let r = Scalar::decode_reduce(&xR_le);
let s = (h + self.x * r) / k;
if (r.iszero() | s.iszero()) == 0 {
let mut sig = [0u8; 64];
sig[..32].copy_from_slice(&bswap32(&r.encode()));
sig[32..].copy_from_slice(&bswap32(&s.encode()));
return sig;
}
}
hmac_start(&mut sh, &K);
sh.update(&V);
sh.update(&[0x00u8]);
let nK = hmac_end(&mut sh, &K);
K[..].copy_from_slice(&nK);
hmac_start(&mut sh, &K);
sh.update(&V);
V[..].copy_from_slice(&hmac_end(&mut sh, &K));
}
}
pub fn prepare_truncate(sig: &[u8]) -> Option<[u8; 64]> {
let siglen = sig.len();
if (siglen & 1) != 0 || siglen == 0 || siglen > 64 {
return None;
}
let numlen = siglen >> 1;
let mut tmp = [0u8; 64];
tmp[(32 - numlen)..32].copy_from_slice(&sig[..numlen]);
tmp[(64 - numlen)..64].copy_from_slice(&sig[numlen..]);
use core::convert::TryFrom;
let rh = u128::from_be_bytes(*<&[u8; 16]>::try_from(
&tmp[ 0..16]).unwrap());
let rl = u128::from_be_bytes(*<&[u8; 16]>::try_from(
&tmp[16..32]).unwrap());
let mut sh = u128::from_be_bytes(*<&[u8; 16]>::try_from(
&tmp[32..48]).unwrap());
let mut sl = u128::from_be_bytes(*<&[u8; 16]>::try_from(
&tmp[48..64]).unwrap());
const NH: u128 = 340282366841710300967557013911933812735u128;
const NL: u128 = 251094175845612772866266697226726352209u128;
const PMN: u128 = 89188191154553853111372247798585809582u128;
if (rh == 0 && rl < PMN) || rh > NH || (rh == NH && rl >= NL)
|| (sh == 0 && sl == 0) || sh > NH || (sh == NH && sl >= NL)
{
return None;
}
if tmp[32] >= 0x80 {
sl = NL.wrapping_sub(sl);
sh = NH.wrapping_sub(sh);
if sl > NL {
sh = sh.wrapping_sub(1);
}
}
let mut nsig = [0u8; 64];
nsig[..32].copy_from_slice(&sig[..32]);
nsig[32..48].copy_from_slice(&sl.to_le_bytes());
nsig[48..64].copy_from_slice(&sh.to_le_bytes());
Some(nsig)
}
}
impl PublicKey {
pub fn decode(buf: &[u8]) -> Option<Self> {
let point = Point::decode(buf)?;
if point.isneutral() != 0 {
return None;
}
Some(Self { point })
}
pub fn encode_compressed(self) -> [u8; 33] {
self.point.encode_compressed()
}
pub fn encode_uncompressed(self) -> [u8; 65] {
self.point.encode_uncompressed()
}
pub fn verify_hash(self, sig: &[u8], hv: &[u8]) -> bool {
let sig_len = sig.len();
if (sig_len & 1) != 0 {
return false;
}
let rlen = sig_len >> 1;
let mut rb = [0u8; 32];
let mut sb = [0u8; 32];
if rlen > 32 {
for i in 0..(rlen - 32) {
if sig[i] != 0 || sig[rlen + i] != 0 {
return false;
}
}
rb[..].copy_from_slice(&sig[(rlen - 32)..rlen]);
sb[..].copy_from_slice(&sig[(sig_len - 32)..sig_len]);
} else {
rb[(32 - rlen)..].copy_from_slice(&sig[..rlen]);
sb[(32 - rlen)..].copy_from_slice(&sig[rlen..]);
}
let (r, cr) = Scalar::decode32(&bswap32(&rb));
if cr == 0 || r.iszero() != 0 {
return false;
}
let (s, cs) = Scalar::decode32(&bswap32(&sb));
if cs == 0 || s.iszero() != 0 {
return false;
}
let mut tmp = [0u8; 32];
if hv.len() >= 32 {
tmp[..].copy_from_slice(&hv[..32]);
} else {
tmp[32 - hv.len() .. 32].copy_from_slice(hv);
}
let h = Scalar::decode_reduce(&bswap32(&tmp));
let w = Scalar::ONE / s;
let R = self.point.mul_add_mulgen_vartime(&(r * w), &(h * w));
let xR_le = bswap32(&R.encode_compressed()[1..33]);
let rr = Scalar::decode_reduce(&xR_le);
return r.equals(rr) != 0;
}
#[cfg(feature = "alloc")]
pub fn verify_trunc_hash(self,
sig: &[u8], rm: usize, hv: &[u8]) -> Option<[u8; 64]>
{
assert!(rm >= 8 && rm <= 32);
if sig.len() != 64 {
return None;
}
let n = (519 - rm) >> 3;
let mut sig2 = [0u8; 64];
sig2[0..n].copy_from_slice(&sig[0..n]);
if (rm & 7) != 0 {
sig2[n - 1] &= 0xFFu8 >> (rm & 7);
}
let mut R_enc = [0u8; 33];
R_enc[0] = 0x02;
R_enc[1..33].copy_from_slice(&sig2[..32]);
let R = Point::decode(&R_enc)?;
let (r, cr) = Scalar::decode32(&bswap32(&sig2[..32]));
if cr == 0 || r.iszero() != 0 {
return None;
}
let (s0, _) = Scalar::decode32(&sig2[32..64]);
let mut tmp = [0u8; 32];
if hv.len() >= 32 {
tmp[..].copy_from_slice(&hv[..32]);
} else {
tmp[32 - hv.len() .. 32].copy_from_slice(hv);
}
let h = Scalar::decode_reduce(&bswap32(&tmp));
let n = 256 - rm; let m = 255 - n;
let k = (m + 1) >> 1;
let U = R.xdouble(n as u32);
let V = self.point.mul_add_mulgen_vartime(&r, &h);
let Rb = s0 * R;
let I = 1usize << (m - k);
let J = 1usize << k;
let Uk = U.xdouble(k as u32);
let mut Ui = Vec::with_capacity(I + 1);
Ui.resize(I + 1, GFp256::ZERO);
let (x0, x1, xq) = Point::to_x_affine_diff(Rb, Rb + Uk);
Point::x_sequence_vartime(x0, x1, xq, &mut Ui[..]);
let mut ux = Vec::with_capacity(Ui.len());
for i in 0..Ui.len() {
let mut tmp = [0u8; 8];
tmp[0..2].copy_from_slice(&(i as u16).to_le_bytes());
tmp[2..8].copy_from_slice(&Ui[i].encode()[0..6]);
ux.push(u64::from_le_bytes(tmp));
}
ux.sort();
let (mut x0, mut x1, xq) = Point::to_x_affine_diff(V, V - U);
let mut jj = 0;
loop {
let mut Vj = [GFp256::ZERO; 100];
let mut blen = J + 1 - jj;
if blen > 100 {
blen = 100;
}
(x0, x1) = Point::x_sequence_vartime(x0, x1, xq, &mut Vj);
for j in 0..blen {
let mut tmp = [0u8; 8];
tmp[0] = 0xFF;
tmp[1] = 0xFF;
tmp[2..8].copy_from_slice(&Vj[j].encode()[0..6]);
let x = u64::from_le_bytes(tmp);
if x < ux[0] {
continue;
}
let mut i1 = 0usize;
let mut i2 = ux.len();
while (i2 - i1) > 1 {
let im = (i1 + i2) >> 1;
if x < ux[im] {
i2 = im;
} else {
i1 = im;
}
}
loop {
let xm = ux[i1];
if ((xm ^ x) >> 16) != 0 {
break;
}
let i = (xm & 0xFFFF) as usize;
if Vj[j].equals(Ui[i]) != 0 {
let j = jj + j; let zUi = Rb + (i as u64) * Uk;
let zVj = V - (j as u64) * U;
let ni = Scalar::from_w64le(0, 0, 0,
(i as u64) << (n + k - 192));
let nj = Scalar::from_w64le(0, 0, 0,
(j as u64) << (n - 192));
let s = if zUi.equals(zVj) != 0 {
s0 + ni + nj
} else {
debug_assert!(zUi.equals(-zVj) != 0);
s0 + ni - nj
};
sig2[32..64].copy_from_slice(&bswap32(&s.encode()));
return Some(sig2);
}
if i1 == 0 {
break;
}
i1 -= 1;
}
}
jj += blen;
if jj >= J + 1 {
break;
}
}
None
}
}
#[derive(Clone, Copy, Debug)]
struct PointAffine {
x: GFp256,
y: GFp256,
}
static PRECOMP_G: [PointAffine; 16] = [
PointAffine { x: GFp256::w64be(0x6B17D1F2E12C4247, 0xF8BCE6E563A440F2,
0x77037D812DEB33A0, 0xF4A13945D898C296),
y: GFp256::w64be(0x4FE342E2FE1A7F9B, 0x8EE7EB4A7C0F9E16,
0x2BCE33576B315ECE, 0xCBB6406837BF51F5) },
PointAffine { x: GFp256::w64be(0x7CF27B188D034F7E, 0x8A52380304B51AC3,
0xC08969E277F21B35, 0xA60B48FC47669978),
y: GFp256::w64be(0x07775510DB8ED040, 0x293D9AC69F7430DB,
0xBA7DADE63CE98229, 0x9E04B79D227873D1) },
PointAffine { x: GFp256::w64be(0x5ECBE4D1A6330A44, 0xC8F7EF951D4BF165,
0xE6C6B721EFADA985, 0xFB41661BC6E7FD6C),
y: GFp256::w64be(0x8734640C4998FF7E, 0x374B06CE1A64A2EC,
0xD82AB036384FB83D, 0x9A79B127A27D5032) },
PointAffine { x: GFp256::w64be(0xE2534A3532D08FBB, 0xA02DDE659EE62BD0,
0x031FE2DB785596EF, 0x509302446B030852),
y: GFp256::w64be(0xE0F1575A4C633CC7, 0x19DFEE5FDA862D76,
0x4EFC96C3F30EE005, 0x5C42C23F184ED8C6) },
PointAffine { x: GFp256::w64be(0x51590B7A515140D2, 0xD784C85608668FDF,
0xEF8C82FD1F5BE524, 0x21554A0DC3D033ED),
y: GFp256::w64be(0xE0C17DA8904A727D, 0x8AE1BF36BF8A7926,
0x0D012F00D4D80888, 0xD1D0BB44FDA16DA4) },
PointAffine { x: GFp256::w64be(0xB01A172A76A4602C, 0x92D3242CB897DDE3,
0x024C740DEBB215B4, 0xC6B0AAE93C2291A9),
y: GFp256::w64be(0xE85C10743237DAD5, 0x6FEC0E2DFBA70379,
0x1C00F7701C7E16BD, 0xFD7C48538FC77FE2) },
PointAffine { x: GFp256::w64be(0x8E533B6FA0BF7B46, 0x25BB30667C01FB60,
0x7EF9F8B8A80FEF5B, 0x300628703187B2A3),
y: GFp256::w64be(0x73EB1DBDE0331836, 0x6D069F83A6F59000,
0x53C73633CB041B21, 0xC55E1A86C1F400B4) },
PointAffine { x: GFp256::w64be(0x62D9779DBEE9B053, 0x4042742D3AB54CAD,
0xC1D238980FCE97DB, 0xB4DD9DC1DB6FB393),
y: GFp256::w64be(0xAD5ACCBD91E9D824, 0x4FF15D771167CEE0,
0xA2ED51F6BBE76A78, 0xDA540A6A0F09957E) },
PointAffine { x: GFp256::w64be(0xEA68D7B6FEDF0B71, 0x878938D51D71F872,
0x9E0ACB8C2C6DF8B3, 0xD79E8A4B90949EE0),
y: GFp256::w64be(0x2A2744C972C9FCE7, 0x87014A964A8EA0C8,
0x4D714FEAA4DE823F, 0xE85A224A4DD048FA) },
PointAffine { x: GFp256::w64be(0xCEF66D6B2A3A993E, 0x591214D1EA223FB5,
0x45CA6C471C48306E, 0x4C36069404C5723F),
y: GFp256::w64be(0x878662A229AAAE90, 0x6E123CDD9D3B4C10,
0x590DED29FE751EEE, 0xCA34BBAA44AF0773) },
PointAffine { x: GFp256::w64be(0x3ED113B7883B4C59, 0x0638379DB0C21CDA,
0x16742ED0255048BF, 0x433391D374BC21D1),
y: GFp256::w64be(0x9099209ACCC4C8A2, 0x24C843AFA4F4C68A,
0x090D04DA5E9889DA, 0xE2F8EEFCE82A3740) },
PointAffine { x: GFp256::w64be(0x741DD5BDA817D95E, 0x4626537320E5D551,
0x79983028B2F82C99, 0xD500C5EE8624E3C4),
y: GFp256::w64be(0x0770B46A9C385FDC, 0x567383554887B154,
0x8EEB912C35BA5CA7, 0x1995FF22CD4481D3) },
PointAffine { x: GFp256::w64be(0x177C837AE0AC495A, 0x61805DF2D85EE2FC,
0x792E284B65EAD58A, 0x98E15D9D46072C01),
y: GFp256::w64be(0x63BB58CD4EBEA558, 0xA24091ADB40F4E72,
0x26EE14C3A1FB4DF3, 0x9C43BBE2EFC7BFD8) },
PointAffine { x: GFp256::w64be(0x54E77A001C3862B9, 0x7A76647F4336DF3C,
0xF126ACBE7A069C5E, 0x5709277324D2920B),
y: GFp256::w64be(0xF599F1BB29F43175, 0x42121F8C05A2E7C3,
0x7171EA7773509008, 0x1BA7C82F60D0B375) },
PointAffine { x: GFp256::w64be(0xF0454DC6971ABAE7, 0xADFB378999888265,
0xAE03AF92DE3A0EF1, 0x63668C63E59B9D5F),
y: GFp256::w64be(0xB5B93EE3592E2D1F, 0x4E6594E51F9643E6,
0x2A3B21CE75B5FA3F, 0x47E59CDE0D034F36) },
PointAffine { x: GFp256::w64be(0x76A94D138A6B4185, 0x8B821C629836315F,
0xCD28392EFF6CA038, 0xA5EB4787E1277C6E),
y: GFp256::w64be(0xA985FE61341F260E, 0x6CB0A1B5E11E8720,
0x8599A0040FC78BAA, 0x0E9DDD724B8C5110) },
];
static PRECOMP_G65: [PointAffine; 16] = [
PointAffine { x: GFp256::w64be(0x031A8747DF8DC746, 0xE4C13D0306960801,
0x53FE448A57324591, 0x794A16BAA05F57B5),
y: GFp256::w64be(0x883A2C64FDA8D586, 0x60E8AA6C1E387A32,
0x1431C18C42B8DEF2, 0x1827EE579C0343FD) },
PointAffine { x: GFp256::w64be(0xA7163C2B9B973C17, 0xF9571975C0D5934A,
0x4ECCAC6096513CCA, 0x015E2E65580B2322),
y: GFp256::w64be(0x308A9A797AF31FA5, 0x63389991545A6B7A,
0xB841A4F4E09952D7, 0x3933B2232197FFE9) },
PointAffine { x: GFp256::w64be(0x3C714524875D4EED, 0xE22A0772517690AC,
0xA18159998EF9AFB9, 0x9AFBD3916A334020),
y: GFp256::w64be(0x7F090565771AAF5C, 0x4889E729FF7F3D8C,
0x152FCAAFE7938C2C, 0x6102A85CBA701655) },
PointAffine { x: GFp256::w64be(0x1BFFAB8C03AB8279, 0x811B3923EF4B991F,
0x02A50C382DB2670C, 0x6CB04A6A5C42A280),
y: GFp256::w64be(0x2982B620CEB1D098, 0x332AC758529F1AAA,
0x982A369AA9D24FB6, 0xC9C742364DDB9261) },
PointAffine { x: GFp256::w64be(0xD9A822BA07B6BC2A, 0xFB88219241F2D6C5,
0x9E5CB1D7B595F7FF, 0xF0EBCB0ED3444C74),
y: GFp256::w64be(0x48E4749ECB370ECB, 0x0E7B8740FF7B504F,
0x2D6ABBD72AEF8A78, 0x5F9ED1AFC2338891) },
PointAffine { x: GFp256::w64be(0x66AA4FD12ADD747A, 0x9D76B8258B28B28C,
0x18B0C59B8AC074B7, 0xE788E04AB021A9BE),
y: GFp256::w64be(0x10C65E609047474C, 0xCA94F6C567E1DC3F,
0x9D64422D106AA108, 0x88B5A3AC03A15A99) },
PointAffine { x: GFp256::w64be(0xE31D414BC13EA842, 0x7C2B1A4EBB312CC8,
0xD10A694EA5FF8400, 0xEF0F43B30A7338BF),
y: GFp256::w64be(0xF8AB200A672A9E53, 0xA87559754BF051FC,
0x35CEE4F5D7185BC0, 0xD23C40B0F878F170) },
PointAffine { x: GFp256::w64be(0x54BC18D7A9989954, 0x7DDC6988D7EE1B3F,
0x2B481AB443DA43FF, 0x68F41305B76A6987),
y: GFp256::w64be(0x4B2C8C1211E6EAF3, 0x7391B851BA73E2FD,
0x52EB8ED4BB73B119, 0xFE457CD05B9AAE49) },
PointAffine { x: GFp256::w64be(0x2C8AA1BBBF526DA4, 0xE347384662E54903,
0xCE0DC533C33CBF11, 0xBDA3E5F081CEC610),
y: GFp256::w64be(0x1A0FC88AF38D3CB8, 0x6BE3230B9C93D0DF,
0x2FE6EA380C43AB69, 0x469EA1B6B2D38B5B) },
PointAffine { x: GFp256::w64be(0xD3DB9B013B334BB5, 0x64A8C9CFFE7D63E6,
0x395E493A27511BEF, 0x5E5E48320038A4D3),
y: GFp256::w64be(0xAF36ED9E441C40EE, 0xDDEC0D6B3E427380,
0xF702E94394A0415C, 0xF5885A882DE9744C) },
PointAffine { x: GFp256::w64be(0xA6C3411CBD535430, 0xA9E5CF878C1CFAEA,
0xB1676B74715F9C2A, 0x904CCE874666F4DF),
y: GFp256::w64be(0x2A2C152EB75FA9B1, 0x4AEC9626316F4989,
0x135DC727867A1E9D, 0x3ACEF8A2C01456D5) },
PointAffine { x: GFp256::w64be(0xAC3857170B8B6252, 0x8C14F0F0B8ACBEAE,
0x074D3FB83DB5ADF3, 0xAAFF87BF8A68FD2D),
y: GFp256::w64be(0x07726BD947412104, 0x78658166B27E4C56,
0xDC5689FD1DD39426, 0x65D518497B48707B) },
PointAffine { x: GFp256::w64be(0xE2ADA2707FC3F4F2, 0x28219C10361C0666,
0xED04CB3E11151FAE, 0xC71275A29DDF5AF3),
y: GFp256::w64be(0x163BA05BF87116C8, 0x447F9D6EC3ECB071,
0x93E3591219126A1B, 0x0D4C0667ACFB630D) },
PointAffine { x: GFp256::w64be(0x2CEFE861BF2C3184, 0xAB2426302BFC3BC7,
0xB410EC4B7440CCA5, 0x68E1C196CDBADC1D),
y: GFp256::w64be(0x1FCBC458DF871736, 0x0F1B16C5D31AECDF,
0x0BB3958FF42B1056, 0xE52E15FFD37537AC) },
PointAffine { x: GFp256::w64be(0xE56081647CE4BC50, 0x579CE8BD6E1C6731,
0xE06F5F6D466A7576, 0x199ACEC99B94CC00),
y: GFp256::w64be(0xAA059E3B7C2C9C86, 0xC60C19BEF5048D65,
0x8C62E0BA91735EF8, 0xB5DDC1B356AC47C7) },
PointAffine { x: GFp256::w64be(0x1F380071781DFF16, 0xF33D8173A6FB4D96,
0xBA770F18355CCA4C, 0xB2A64C6196260250),
y: GFp256::w64be(0xB1521EC4BA6C681D, 0xA33705176CA2CF62,
0x1B8567660590D693, 0xB1519B2E6B011955) },
];
static PRECOMP_G130: [PointAffine; 16] = [
PointAffine { x: GFp256::w64be(0x2890D721E57E1961, 0x18E63ADD579547F0,
0xACAD16E63BE0AEA8, 0xF6F1D3AC4D771F0C),
y: GFp256::w64be(0x69B5B8159DDC032A, 0xAF77E1D1416752EC,
0x7DC0E7F77EF54069, 0x0A5728ECB5890D78) },
PointAffine { x: GFp256::w64be(0x7B8B8867DD4D9C6F, 0x81690628033DE305,
0xD4E3FF5E71DA1781, 0x4F5822EFAC7E9E44),
y: GFp256::w64be(0x8BC6273E511680B4, 0x2246073C7DD5ADB5,
0x64057E6DBBD72365, 0x0767022AA8CD12C3) },
PointAffine { x: GFp256::w64be(0x05F0C3CABE40EDE9, 0x02FAEA8E759ACD21,
0xCF8A00249E4D1558, 0xEEE143C1F0F870D2),
y: GFp256::w64be(0x34B55D934F6D2C56, 0xBCE7A5998AB1AC23,
0xC2F725737AEB5F8A, 0x5F537C956E60E8CC) },
PointAffine { x: GFp256::w64be(0x9022E314949CCF3E, 0x8937542B8CDEC18E,
0xA2F8D5618688CE24, 0x1EBD8BAC137DE736),
y: GFp256::w64be(0x2FAE5E4F2904A394, 0x66D0BB045226CE08,
0x7F49366C44EA7657, 0xF4EF5C0844C42ECC) },
PointAffine { x: GFp256::w64be(0xA7F78E1EC93CBBD6, 0xF8FC6D4127ED7269,
0xB9D7F4F0A675F38F, 0x0292ECB3AED00393),
y: GFp256::w64be(0x74385589986B6CFB, 0x55B693F3E38D980F,
0xE99F2570EB82ABA9, 0x19D07787B7FEF35A) },
PointAffine { x: GFp256::w64be(0x0029C229E3736FCA, 0x260FA106D35E9AEA,
0xE5CB8D2F032C89E8, 0xC9FBED5AC0E99BE1),
y: GFp256::w64be(0xDCE5DE5CBAE2D493, 0x986D607FEF4AACD3,
0x5C1B783D383671FE, 0x5C3583389E77EDB0) },
PointAffine { x: GFp256::w64be(0x847021C276877E98, 0xE4B6CE7093E79C53,
0x320440AE7941CFEA, 0x0FA90FA2B7F21984),
y: GFp256::w64be(0x72B8BC670713B0C8, 0x7902B8C7723B15EC,
0x45A79737F0DD70AB, 0xC8C8A0CA549DEAE8) },
PointAffine { x: GFp256::w64be(0xA77663F5FCDF189C, 0xC2731F7801B1133E,
0xE130A96964396297, 0x872E52CF757A603C),
y: GFp256::w64be(0x4E139CBDADDAFC58, 0xDAE982FA5476A35A,
0x8AB86C568CBACE48, 0xD91745804CA8E468) },
PointAffine { x: GFp256::w64be(0xE5D817CA33C4E2FE, 0x60C06F3595DED4B8,
0x00FE36FF7435D008, 0x603810E5CC6A453E),
y: GFp256::w64be(0xA4C9D402134C2096, 0x7B562F4E55850BA0,
0xDF8B7D3BCFC9A287, 0xC62349BAEC9EE85D) },
PointAffine { x: GFp256::w64be(0x85D2322A5DAEBAF1, 0xCFA07F5F23768F84,
0x0C2ACF8A3A05AF3D, 0x13EF0C6AB6531CEE),
y: GFp256::w64be(0xFBB6BF19376E06EF, 0x76A17B861DDA119F,
0xA974DF60FBA1B683, 0x5448F9E51FFF61F6) },
PointAffine { x: GFp256::w64be(0x6D420C785F05B0D1, 0x792AAF68692B6A7E,
0xD4180CE48549F248, 0xD2E327E28014ED0D),
y: GFp256::w64be(0x706934B5ECC0921B, 0x03C0F2593F66094C,
0x64A84889C456A6F0, 0x27C246F735A6D65A) },
PointAffine { x: GFp256::w64be(0x6E5872E3076FE945, 0xFB0F2D3F1AF7857A,
0xF73F35183273C051, 0x91706CB8D09B01F5),
y: GFp256::w64be(0x4213C02EC8D77171, 0x80CC1D4AF3BEF0EB,
0xC13179D4E09A85A7, 0xC30758D9ABCD5FDE) },
PointAffine { x: GFp256::w64be(0x56F5C4B85C0574DC, 0x078E6CFA9B9AF7F9,
0xB7A0E24BB0CB03AC, 0x2EC6F1FFBFED0AF3),
y: GFp256::w64be(0x54E716D27CA28344, 0x99C70ECBD1B77EFC,
0x36CCC70A13343147, 0xB16512E5EB7720CB) },
PointAffine { x: GFp256::w64be(0x604AC042B04668BB, 0xE0D905ACA59AB261,
0x2625F0B09E37C379, 0x6C0882668EBB9BB6),
y: GFp256::w64be(0x370FA451C3ECD3E4, 0xD603305526FFAEBF,
0xFDBAAE00E30B932F, 0xDB5172B771028158) },
PointAffine { x: GFp256::w64be(0xB5DC5FC512D1C157, 0x66F5CBF729D95ECB,
0x68F2A620A52E5FE3, 0x2CC1CF471362C215),
y: GFp256::w64be(0x6EFA9672CA18B8CE, 0xAC9ADA314F5285DA,
0x3FC7CF1166E0E7DB, 0xE925490007E98290) },
PointAffine { x: GFp256::w64be(0x1A7098D2DB889A11, 0x12911D2965F2870E,
0xA93D696BF79B5582, 0xE83E2130461DFFE4),
y: GFp256::w64be(0x39D474F5EE8B69FA, 0xE5A42C936F76F327,
0x68682783DE26B553, 0xF3BA5EED161315DA) },
];
static PRECOMP_G195: [PointAffine; 16] = [
PointAffine { x: GFp256::w64be(0x9A79BFBFE71E347F, 0x4D6C6698316797E2,
0xF5AC2A3900F5ABF0, 0xC409332DE46E2050),
y: GFp256::w64be(0xE98B4DE6D316E200, 0xB6F671F3B224EFA9,
0xCA94FACCB6DFDE31, 0x7A3F4781926250D2) },
PointAffine { x: GFp256::w64be(0xAC25DA80089CF4E0, 0x33D4DB5710FF5936,
0xFD683B4D0DAB013E, 0x6EEF62FF4514C6FD),
y: GFp256::w64be(0xEBC69D985CB44C7B, 0x883DA9312A1B338C,
0x810983E8243BF37A, 0x60B5397705830541) },
PointAffine { x: GFp256::w64be(0x3A52D92C9B4DF939, 0xD0B45C92FC82055A,
0x6087250028AC0ECD, 0x3A611C1E24B91CD0),
y: GFp256::w64be(0x9EBBCBDB18D87820, 0xE0362AC11F589476,
0xF9D2197601A1C427, 0xDA58C4ED72313BA9) },
PointAffine { x: GFp256::w64be(0xB467CD65660C13B8, 0x4AEC42B5296BC037,
0xC1E6B5EA71A0D289, 0xB456511069962F3C),
y: GFp256::w64be(0xDC91B9BC4D36FFEA, 0xBB3F5D2A011664AC,
0x3CB212DF6CBDA472, 0xF75584CB22877596) },
PointAffine { x: GFp256::w64be(0xCB32B06A74454973, 0x61DC3CD62B330851,
0xB5A5817C274859C8, 0x4BD01EC7B5C8A53E),
y: GFp256::w64be(0xEECBCB591D8E55F7, 0x2DBEDABC226784F1,
0xAED376EDC810D12F, 0xD7E9D40D0709AB85) },
PointAffine { x: GFp256::w64be(0xEEA7E66C49BA3C8B, 0xB4D748671E165547,
0xE631E4DC5427AD60, 0x81941C7E32FD0E3D),
y: GFp256::w64be(0x83FED45B9F889261, 0x28843F27BE9B7D98,
0x5ACBADA23019E3CC, 0x10411F68D91D5868) },
PointAffine { x: GFp256::w64be(0xF3736791C368A886, 0x44D8B2AB44362269,
0x452772FC2EBBB531, 0xD961A14460FFAF46),
y: GFp256::w64be(0xFF18EA13C19FA5F8, 0x0FE7B2615346DF42,
0xCED765F8C33E1679, 0xBEE3806EA38FE7AC) },
PointAffine { x: GFp256::w64be(0x92F9A6F93FA37761, 0x979280DE26DA6CDE,
0x08533ABEEF2160F4, 0x919B1597B43C7E8D),
y: GFp256::w64be(0xBF618D715147AFE8, 0xED41D3A6F5E542DF,
0x7309284ECEA31289, 0x7746055552BF1285) },
PointAffine { x: GFp256::w64be(0xA022A1FA97E7AAFE, 0x3D78A9AFCD130CD8,
0x6D2CEA57032119E2, 0x25475B10E116E28A),
y: GFp256::w64be(0x39A9060D8AE899FF, 0x294E50155C1A2436,
0x687F6DBBF07C9BF2, 0x83CCB7FD708A2008) },
PointAffine { x: GFp256::w64be(0x9A3DE2D3E93E21BD, 0xBAD194B35403C67B,
0x7DDFFE6C44408E5D, 0x119F14F26CCB63B3),
y: GFp256::w64be(0x2F809B90611112C8, 0x809F2736EE813C4C,
0x49C01D9FEF582260, 0x01C532977DF93FCF) },
PointAffine { x: GFp256::w64be(0x3AABC6CEC406EFDE, 0x93A0AAEC8366DE41,
0x33D6D33959266E23, 0xA38069C0A5CEDE86),
y: GFp256::w64be(0xF9B11C9A08A65B42, 0xBE21897E20D27EB3,
0xEE6C0F0C0FDD87AD, 0xF5E941F6788BEA75) },
PointAffine { x: GFp256::w64be(0x3CC4767A06772486, 0x65FBB469F6E48D44,
0x7DB4BA1F065935FB, 0xB5CD34F827D3C9FF),
y: GFp256::w64be(0x557C538D8CD381AD, 0x94F22765E37B7EDF,
0x772241168378473A, 0x3016C53CC5AA7383) },
PointAffine { x: GFp256::w64be(0x81E200EB9A14795D, 0xC21A735B26096917,
0x814C37604036C2E1, 0x1847121C6DD6F7D4),
y: GFp256::w64be(0x4F3DBBD140393479, 0x0AF1ABB04967D8AB,
0x2215774AA9EF4A5F, 0xC653CEAE0007051D) },
PointAffine { x: GFp256::w64be(0xA7C382F4B53B92DB, 0x05100D30123FADAF,
0x34896F70BA7F6D8B, 0xE4ECA34DD63F1117),
y: GFp256::w64be(0x1B91E5116761BF88, 0x0459F777705DCFB5,
0xAE4EB76ED3C4A68C, 0xC1220C5E1934CB9A) },
PointAffine { x: GFp256::w64be(0x46D7E1C662885744, 0x35E92201E54A33E8,
0x7399020B7D586074, 0x6AC4CE68ECB57693),
y: GFp256::w64be(0x98E98E39CB7F8AD0, 0x412F1731CBBBAED9,
0x2CA811498DC3BE4E, 0x14747481CA2A8770) },
PointAffine { x: GFp256::w64be(0x5CE4FD836044BAF3, 0xA1623065BCE83B11,
0xFD7516A5B209D887, 0xD79A7081AFAEFC6A),
y: GFp256::w64be(0x61042108AA50F368, 0x1E31BC1EA832C714,
0x4ABFBD4AB9E4ACCE, 0x38606DFBBF9DB9A6) },
];
#[cfg(test)]
mod tests {
use super::{Point, Scalar, PrivateKey};
use sha2::{Sha256, Digest};
#[cfg(feature = "alloc")]
use crate::Vec;
#[cfg(feature = "alloc")]
use crate::field::GFp256;
#[test]
fn base_arith() {
const EP0: [u8; 1] = [ 0 ];
const EPC: [[u8; 33]; 7] = [
[
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
],
[
0x02,
0xAA, 0x0E, 0xB9, 0x89, 0xA0, 0x7C, 0x30, 0xF9,
0xEC, 0x83, 0xC1, 0xF1, 0x02, 0x76, 0x2F, 0x75,
0x2D, 0x77, 0xD8, 0xD7, 0x22, 0x71, 0xE5, 0x5B,
0xDB, 0xA6, 0x21, 0x6A, 0x97, 0x6B, 0x1E, 0xAF
],
[
0x02,
0xBB, 0x49, 0xE8, 0xA7, 0x67, 0x7E, 0x4C, 0xBA,
0xB7, 0x58, 0x55, 0xB3, 0x09, 0xF3, 0x33, 0x6D,
0xAD, 0xB8, 0xAA, 0xFF, 0xF9, 0x54, 0x7A, 0x39,
0xC4, 0xB5, 0x86, 0x8D, 0x2F, 0xE9, 0xD4, 0xD6
],
[
0x02,
0xC4, 0xC3, 0x08, 0x93, 0x37, 0x35, 0x33, 0x1D,
0xBD, 0x22, 0xD8, 0x4A, 0x02, 0x6F, 0xEA, 0x53,
0xA1, 0x86, 0x42, 0xF6, 0x27, 0xEF, 0x9E, 0xB0,
0xD6, 0xE2, 0xA6, 0x8A, 0x2E, 0xB8, 0xB4, 0x7C
],
[
0x02,
0x7F, 0xAC, 0x28, 0xE6, 0xB5, 0x2B, 0xA8, 0x2E,
0x83, 0x1E, 0xDC, 0x29, 0x3D, 0x59, 0x73, 0xB9,
0xC6, 0x5F, 0x43, 0xF6, 0x4A, 0xB4, 0xF3, 0x7C,
0x38, 0x58, 0x80, 0x2A, 0x99, 0x4F, 0x34, 0xE8
],
[
0x03,
0xAA, 0x1A, 0x33, 0x26, 0xBF, 0xBB, 0x57, 0x8D,
0x4B, 0x16, 0xBD, 0x94, 0xA1, 0x8E, 0x88, 0x5C,
0x6F, 0x53, 0x6E, 0xE1, 0xF4, 0x6A, 0x99, 0xAF,
0x43, 0xF0, 0x91, 0x2E, 0xFD, 0x44, 0x6B, 0x85
],
[
0x02,
0x14, 0x58, 0xDE, 0x7A, 0x34, 0x09, 0x4E, 0x68,
0x31, 0x59, 0x2D, 0x48, 0x13, 0x5F, 0xDC, 0xC5,
0x8A, 0xA5, 0x25, 0xBF, 0x1B, 0xF7, 0x65, 0xCE,
0x40, 0x5B, 0x53, 0x36, 0x2F, 0x36, 0xDE, 0xA4
],
];
const EPU: [[u8; 65]; 7] = [
[
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
],
[
0x04,
0xAA, 0x0E, 0xB9, 0x89, 0xA0, 0x7C, 0x30, 0xF9,
0xEC, 0x83, 0xC1, 0xF1, 0x02, 0x76, 0x2F, 0x75,
0x2D, 0x77, 0xD8, 0xD7, 0x22, 0x71, 0xE5, 0x5B,
0xDB, 0xA6, 0x21, 0x6A, 0x97, 0x6B, 0x1E, 0xAF,
0x7D, 0x04, 0xEB, 0xEF, 0x40, 0xBF, 0x57, 0xF4,
0xAF, 0x34, 0xD2, 0xEB, 0x59, 0x14, 0x84, 0xFA,
0xD2, 0x67, 0xBB, 0x92, 0x28, 0x8A, 0x6C, 0x8C,
0x88, 0x3D, 0xD1, 0x24, 0xA7, 0xF9, 0xB8, 0xD6
],
[
0x04,
0xBB, 0x49, 0xE8, 0xA7, 0x67, 0x7E, 0x4C, 0xBA,
0xB7, 0x58, 0x55, 0xB3, 0x09, 0xF3, 0x33, 0x6D,
0xAD, 0xB8, 0xAA, 0xFF, 0xF9, 0x54, 0x7A, 0x39,
0xC4, 0xB5, 0x86, 0x8D, 0x2F, 0xE9, 0xD4, 0xD6,
0x53, 0x7B, 0xB0, 0x46, 0x10, 0xF8, 0x0E, 0x00,
0x43, 0xA7, 0x9F, 0x52, 0xE4, 0xF8, 0xB8, 0x5C,
0x88, 0x74, 0x5E, 0x72, 0xE0, 0xCD, 0xE9, 0x70,
0x4B, 0x19, 0x82, 0xFA, 0x92, 0x97, 0x6B, 0xF6
],
[
0x04,
0xC4, 0xC3, 0x08, 0x93, 0x37, 0x35, 0x33, 0x1D,
0xBD, 0x22, 0xD8, 0x4A, 0x02, 0x6F, 0xEA, 0x53,
0xA1, 0x86, 0x42, 0xF6, 0x27, 0xEF, 0x9E, 0xB0,
0xD6, 0xE2, 0xA6, 0x8A, 0x2E, 0xB8, 0xB4, 0x7C,
0x86, 0xB7, 0x70, 0xA3, 0xDE, 0x94, 0x0A, 0x78,
0x6F, 0xC9, 0x97, 0x0E, 0x9B, 0x41, 0x8A, 0x7E,
0x26, 0xEA, 0xCD, 0x70, 0x52, 0x3F, 0x17, 0xA1,
0x2C, 0x6A, 0xF4, 0xFD, 0x00, 0x47, 0xB5, 0x2C
],
[
0x04,
0x7F, 0xAC, 0x28, 0xE6, 0xB5, 0x2B, 0xA8, 0x2E,
0x83, 0x1E, 0xDC, 0x29, 0x3D, 0x59, 0x73, 0xB9,
0xC6, 0x5F, 0x43, 0xF6, 0x4A, 0xB4, 0xF3, 0x7C,
0x38, 0x58, 0x80, 0x2A, 0x99, 0x4F, 0x34, 0xE8,
0x80, 0xE9, 0x49, 0x0B, 0xFB, 0x97, 0x75, 0x84,
0x37, 0xC6, 0xE2, 0x82, 0x68, 0x6C, 0x08, 0x7D,
0xDB, 0x21, 0x23, 0xDC, 0x44, 0x56, 0x15, 0xB0,
0x01, 0x71, 0x61, 0x42, 0x79, 0xC3, 0x64, 0x0C
],
[
0x04,
0xAA, 0x1A, 0x33, 0x26, 0xBF, 0xBB, 0x57, 0x8D,
0x4B, 0x16, 0xBD, 0x94, 0xA1, 0x8E, 0x88, 0x5C,
0x6F, 0x53, 0x6E, 0xE1, 0xF4, 0x6A, 0x99, 0xAF,
0x43, 0xF0, 0x91, 0x2E, 0xFD, 0x44, 0x6B, 0x85,
0x78, 0x46, 0x19, 0xA3, 0xEF, 0xE1, 0xD0, 0xCC,
0xD8, 0x61, 0x6A, 0xF1, 0x14, 0x47, 0xBF, 0xD7,
0x7E, 0x36, 0xB5, 0xF7, 0x8D, 0x53, 0x1C, 0xC8,
0x6B, 0x8D, 0x7B, 0x2B, 0x58, 0xE6, 0x26, 0x8F
],
[
0x04,
0x14, 0x58, 0xDE, 0x7A, 0x34, 0x09, 0x4E, 0x68,
0x31, 0x59, 0x2D, 0x48, 0x13, 0x5F, 0xDC, 0xC5,
0x8A, 0xA5, 0x25, 0xBF, 0x1B, 0xF7, 0x65, 0xCE,
0x40, 0x5B, 0x53, 0x36, 0x2F, 0x36, 0xDE, 0xA4,
0x20, 0x27, 0xDF, 0xC5, 0x9C, 0x29, 0xD1, 0xDB,
0x2D, 0x5B, 0x67, 0x6F, 0x36, 0xC8, 0xC7, 0xDA,
0xC1, 0x63, 0x76, 0x69, 0xD1, 0xAA, 0xD8, 0x46,
0x63, 0x26, 0xFE, 0xD2, 0x0F, 0x62, 0x6B, 0x9C
],
];
let P0 = Point::decode(&EP0).unwrap();
assert!(P0.isneutral() == 0xFFFFFFFF);
let mut PP = [P0; 7];
for i in 1..7 {
let P = Point::decode(&EPC[i]).unwrap();
let Q = Point::decode(&EPU[i]).unwrap();
assert!(P.isneutral() == 0);
assert!(Q.isneutral() == 0);
assert!(P.equals(Q) == 0xFFFFFFFF);
assert!(P.encode_compressed() == EPC[i]);
assert!(P.encode_uncompressed() == EPU[i]);
PP[i] = P;
}
let P0 = PP[0];
let P1 = PP[1];
let P2 = PP[2];
let P3 = PP[3];
let P4 = PP[4];
let P5 = PP[5];
let P6 = PP[6];
for i in 1..7 {
assert!(PP[i].equals(PP[i - 1]) == 0);
let Q = PP[i - 1] + PP[1];
assert!(PP[i].equals(Q) == 0xFFFFFFFF);
assert!((Q + Point::NEUTRAL).equals(Q) == 0xFFFFFFFF);
let R = Q + P0;
assert!(PP[i].equals(R) == 0xFFFFFFFF);
}
let Q2 = P1 + P1;
assert!(Q2.encode_compressed() == EPC[2]);
assert!(Q2.equals(P2) == 0xFFFFFFFF);
let R2 = P1.double();
assert!(R2.encode_compressed() == EPC[2]);
assert!(R2.equals(P2) == 0xFFFFFFFF);
assert!(R2.equals(Q2) == 0xFFFFFFFF);
let Q3 = P2 + P1;
assert!(Q3.encode_compressed() == EPC[3]);
assert!(Q3.equals(P3) == 0xFFFFFFFF);
let R3 = Q2 + P1;
assert!(R3.encode_compressed() == EPC[3]);
assert!(R3.equals(P3) == 0xFFFFFFFF);
assert!(R3.equals(Q3) == 0xFFFFFFFF);
let Q4 = Q2.double();
assert!(Q4.encode_compressed() == EPC[4]);
assert!(Q4.equals(P4) == 0xFFFFFFFF);
let R4 = P1.xdouble(2);
assert!(R4.encode_compressed() == EPC[4]);
assert!(R4.equals(P4) == 0xFFFFFFFF);
assert!(R4.equals(Q4) == 0xFFFFFFFF);
let R4 = P1 + Q3;
assert!(R4.encode_compressed() == EPC[4]);
assert!(R4.equals(P4) == 0xFFFFFFFF);
assert!(R4.equals(Q4) == 0xFFFFFFFF);
let Q5 = Q3 + R2;
assert!(Q5.encode_compressed() == EPC[5]);
assert!(Q5.equals(P5) == 0xFFFFFFFF);
let R5 = R3 + Q2;
assert!(R5.encode_compressed() == EPC[5]);
assert!(R5.equals(P5) == 0xFFFFFFFF);
assert!(R5.equals(Q5) == 0xFFFFFFFF);
assert!((R5 - Q3).equals(Q2) == 0xFFFFFFFF);
let Q6 = Q3.double();
assert!(Q6.encode_compressed() == EPC[6]);
assert!(Q6.equals(P6) == 0xFFFFFFFF);
let R6 = Q2 + Q4;
assert!(R6.encode_compressed() == EPC[6]);
assert!(R6.equals(P6) == 0xFFFFFFFF);
assert!(R6.equals(Q6) == 0xFFFFFFFF);
let mut P = Q6;
let mut Q = R6;
for _ in 0..8 {
P += P;
}
Q.set_xdouble(8);
assert!(P.equals(Q) == 0xFFFFFFFF);
let P = P1 + P0.double();
assert!(P.equals(P1) == 0xFFFFFFFF);
assert!(P.equals(P2) == 0x00000000);
}
#[test]
fn mulgen() {
let s = Scalar::w64be(0x7DC39B763DF3A5EA, 0x46AC87887B246E48,
0xD9DC3839C0D466E4, 0x6DFE006C126C829B);
let enc: [u8; 33] = [
0x02,
0x53, 0x13, 0x52, 0x93, 0xE1, 0xF3, 0xD3, 0xBE,
0x74, 0xBF, 0x7D, 0x50, 0xD9, 0x9C, 0xA0, 0x85,
0x41, 0xB0, 0x36, 0xE0, 0x9D, 0xB7, 0x83, 0xFC,
0x79, 0x08, 0xA0, 0xDA, 0xF3, 0x94, 0xDA, 0x6F
];
let R = Point::decode(&enc).unwrap();
let P = Point::BASE * s;
assert!(P.equals(R) == 0xFFFFFFFF);
assert!(P.encode_compressed() == enc);
let Q = Point::mulgen(&s);
assert!(Q.equals(R) == 0xFFFFFFFF);
assert!(Q.encode_compressed() == enc);
}
#[test]
fn mul() {
let mut sh = Sha256::new();
for i in 0..20 {
sh.update(((2 * i + 0) as u64).to_le_bytes());
let v1 = sh.finalize_reset();
sh.update(((2 * i + 1) as u64).to_le_bytes());
let v2 = sh.finalize_reset();
let s1 = Scalar::decode_reduce(&v1);
let s2 = Scalar::decode_reduce(&v2);
let s3 = s1 * s2;
let P1 = Point::mulgen(&s1);
let Q1 = s1 * Point::BASE;
assert!(P1.equals(Q1) == 0xFFFFFFFF);
let P2 = Point::mulgen(&s3);
let Q2 = s2 * Q1;
assert!(P2.equals(Q2) == 0xFFFFFFFF);
}
}
#[test]
fn mul_add_mulgen() {
let mut sh = Sha256::new();
for i in 0..20 {
sh.update(((3 * i + 0) as u64).to_le_bytes());
let v1 = sh.finalize_reset();
sh.update(((3 * i + 1) as u64).to_le_bytes());
let v2 = sh.finalize_reset();
sh.update(((3 * i + 2) as u64).to_le_bytes());
let v3 = sh.finalize_reset();
let A = Point::mulgen(&Scalar::decode_reduce(&v1));
let u = Scalar::decode_reduce(&v2);
let v = Scalar::decode_reduce(&v3);
let R1 = u * A + Point::mulgen(&v);
let R2 = A.mul_add_mulgen_vartime(&u, &v);
assert!(R1.equals(R2) == 0xFFFFFFFF);
}
}
#[test]
fn verify_helper() {
let mut sh = Sha256::new();
for i in 0..20 {
sh.update(((3 * i + 0) as u64).to_le_bytes());
let v1 = sh.finalize_reset();
sh.update(((3 * i + 1) as u64).to_le_bytes());
let v2 = sh.finalize_reset();
sh.update(((3 * i + 2) as u64).to_le_bytes());
let v3 = sh.finalize_reset();
let Q = Point::mulgen(&Scalar::decode_reduce(&v1));
let s = Scalar::decode_reduce(&v2);
let k = Scalar::decode_reduce(&v3);
let R = Point::mulgen(&s) - k * Q;
assert!(Q.verify_helper_vartime(&R, &s, &k));
assert!(!Q.verify_helper_vartime(&R, &(s + Scalar::ONE), &k));
assert!(!Q.verify_helper_vartime(&R, &s, &(k + Scalar::ONE)));
assert!(!Q.verify_helper_vartime(&(R + Point::BASE), &s, &k));
assert!(!(Q + Point::BASE).verify_helper_vartime(&R, &s, &k));
}
}
#[cfg(feature = "alloc")]
#[test]
fn x_sequence() {
fn tt(P0: Point, P1: Point, n: usize) {
let mut xx = Vec::with_capacity(n);
xx.resize(n, GFp256::ZERO);
let Q = P1 - P0;
let (x0, _, _) = P0.to_affine();
let (x1, _, _) = P1.to_affine();
let (xq, _, _) = Q.to_affine();
let (xf0, xf1) = Point::x_sequence_vartime(x0, x1, xq, &mut xx[..]);
let mut T = P0;
for i in 0..n {
if T.isneutral() != 0 {
assert!(xx[i].equals(GFp256::ONE) != 0);
} else {
assert!(T.X.equals(xx[i] * T.Z) != 0);
}
T += Q;
}
let T0 = T;
let T1 = T + Q;
if T0.isneutral() != 0 {
assert!(xf0.equals(GFp256::ONE) != 0);
} else {
assert!(T0.X.equals(xf0 * T0.Z) != 0);
}
if T1.isneutral() != 0 {
assert!(xf1.equals(GFp256::ONE) != 0);
} else {
assert!(T1.X.equals(xf1 * T1.Z) != 0);
}
}
let mut sh = Sha256::new();
sh.update(&[0u8]);
let U = Point::mulgen(&Scalar::decode_reduce(&sh.finalize_reset()[..]));
sh.update(&[1u8]);
let V = Point::mulgen(&Scalar::decode_reduce(&sh.finalize_reset()[..]));
tt(U, V, 0);
tt(U, V, 1);
tt(U, V, 2);
tt(U, V, 3);
tt(U, V, 100);
tt(U, V, 101);
tt(U, V, 102);
tt(5 * U, 4 * U, 3);
tt(5 * U, 4 * U, 4);
tt(5 * U, 4 * U, 5);
tt(5 * U, 4 * U, 6);
tt(5 * U, 4 * U, 7);
tt(U, U, 10);
let mut Q_enc = [0u8; 33];
Q_enc[0] = 0x02;
let Q = Point::decode(&Q_enc).unwrap();
tt(U, U + Q, 10);
tt(Q - 5 * U, Q - 4 * U, 10);
}
#[test]
fn signatures() {
let priv_enc: [u8; 32] = [
0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16,
0x6B, 0x5C, 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93,
0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12,
0x7B, 0x8A, 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21,
];
let pub_enc: [u8; 65] = [
0x04,
0x60, 0xFE, 0xD4, 0xBA, 0x25, 0x5A, 0x9D, 0x31,
0xC9, 0x61, 0xEB, 0x74, 0xC6, 0x35, 0x6D, 0x68,
0xC0, 0x49, 0xB8, 0x92, 0x3B, 0x61, 0xFA, 0x6C,
0xE6, 0x69, 0x62, 0x2E, 0x60, 0xF2, 0x9F, 0xB6,
0x79, 0x03, 0xFE, 0x10, 0x08, 0xB8, 0xBC, 0x99,
0xA4, 0x1A, 0xE9, 0xE9, 0x56, 0x28, 0xBC, 0x64,
0xF2, 0xF1, 0xB2, 0x0C, 0x2D, 0x7E, 0x9F, 0x51,
0x77, 0xA3, 0xC2, 0x94, 0xD4, 0x46, 0x22, 0x99,
];
let msg1: &[u8] = b"sample";
let expected_sig1: [u8; 64] = [
0xEF, 0xD4, 0x8B, 0x2A, 0xAC, 0xB6, 0xA8, 0xFD,
0x11, 0x40, 0xDD, 0x9C, 0xD4, 0x5E, 0x81, 0xD6,
0x9D, 0x2C, 0x87, 0x7B, 0x56, 0xAA, 0xF9, 0x91,
0xC3, 0x4D, 0x0E, 0xA8, 0x4E, 0xAF, 0x37, 0x16,
0xF7, 0xCB, 0x1C, 0x94, 0x2D, 0x65, 0x7C, 0x41,
0xD4, 0x36, 0xC7, 0xA1, 0xB6, 0xE2, 0x9F, 0x65,
0xF3, 0xE9, 0x00, 0xDB, 0xB9, 0xAF, 0xF4, 0x06,
0x4D, 0xC4, 0xAB, 0x2F, 0x84, 0x3A, 0xCD, 0xA8,
];
let msg2: &[u8] = b"test";
let expected_sig2: [u8; 64] = [
0xF1, 0xAB, 0xB0, 0x23, 0x51, 0x83, 0x51, 0xCD,
0x71, 0xD8, 0x81, 0x56, 0x7B, 0x1E, 0xA6, 0x63,
0xED, 0x3E, 0xFC, 0xF6, 0xC5, 0x13, 0x2B, 0x35,
0x4F, 0x28, 0xD3, 0xB0, 0xB7, 0xD3, 0x83, 0x67,
0x01, 0x9F, 0x41, 0x13, 0x74, 0x2A, 0x2B, 0x14,
0xBD, 0x25, 0x92, 0x6B, 0x49, 0xC6, 0x49, 0x15,
0x5F, 0x26, 0x7E, 0x60, 0xD3, 0x81, 0x4B, 0x4C,
0x0C, 0xC8, 0x42, 0x50, 0xE4, 0x6F, 0x00, 0x83,
];
let skey = PrivateKey::decode(&priv_enc).unwrap();
let pkey = skey.to_public_key();
assert!(pkey.encode_uncompressed() == pub_enc);
let mut sh = Sha256::new();
sh.update(&msg1);
let hv1: [u8; 32] = sh.finalize_reset().into();
let sig1 = skey.sign_hash(&hv1, &[]);
assert!(sig1 == expected_sig1);
sh.update(&msg2);
let hv2: [u8; 32] = sh.finalize_reset().into();
let sig2 = skey.sign_hash(&hv2, &[]);
assert!(sig2 == expected_sig2);
assert!(pkey.verify_hash(&sig1, &hv1));
assert!(pkey.verify_hash(&sig2, &hv2));
assert!(!pkey.verify_hash(&sig1, &hv2));
assert!(!pkey.verify_hash(&sig2, &hv1));
}
#[cfg(feature = "alloc")]
#[test]
fn signatures_trunc() {
let mut seed = [0u8; 48];
let mut sh = Sha256::new();
sh.update(&[0u8]);
seed[0..32].copy_from_slice(&sh.finalize_reset()[..]);
sh.update(&[1u8]);
seed[32..48].copy_from_slice(&sh.finalize_reset()[0..16]);
let skey = PrivateKey::from_seed(&seed);
let pkey = skey.to_public_key();
for i in 0..2 {
let mut msg = [0u8; 8];
msg[..].copy_from_slice(&(i as u64).to_le_bytes());
sh.update(&msg);
let hv = sh.finalize_reset();
let sig1 = skey.sign_hash(&hv[..], &[]);
let mut sig2 = PrivateKey::prepare_truncate(&sig1).unwrap();
sig2[63] = 0;
for rm in 8..(if i == 0 { 33 } else { 25 }) {
let n = 512 - rm;
sig2[n >> 3] &= !(0x01u8 << (n & 7));
let vv = pkey.verify_trunc_hash(&sig2, rm, &hv[..]);
assert!(vv.is_some());
let sig3 = vv.unwrap();
assert!(pkey.verify_hash(&sig3, &hv[..]));
msg[0] ^= 1;
assert!(pkey.verify_trunc_hash(&sig2, rm, &msg).is_none());
msg[0] ^= 1;
}
}
}
}