use core::fmt;
use core::ops::Range;
use super::util;
use crate::error::{Error, KeyFormatError};
use crate::low;
use crate::mid::rng::{RandomSource, SystemRandom};
mod precomp;
#[derive(Clone, Debug)]
pub(crate) struct PublicKey {
point: AffineMontPoint,
}
impl PublicKey {
pub(crate) const BYTES: usize = 1 + FieldElement::BYTES + FieldElement::BYTES;
pub(crate) fn from_x962_uncompressed(bytes: &[u8]) -> Result<Self, Error> {
let _entry = low::Entry::new_public();
let point = AffineMontPoint::from_x962_uncompressed(bytes)?;
Ok(Self { point })
}
}
#[derive(Clone, Debug)]
pub(crate) struct VerifyingKey {
precomp_w5: JacobianMontPointTableW5,
}
impl VerifyingKey {
pub(crate) fn from_x962_uncompressed(bytes: &[u8]) -> Result<Self, Error> {
let PublicKey { point } = PublicKey::from_x962_uncompressed(bytes)?;
Ok(Self {
precomp_w5: point.public_precomp_w5(),
})
}
pub(crate) fn raw_ecdsa_verify(&self, r: &Scalar, s: &Scalar, e: &Scalar) -> Result<(), Error> {
let s_inv = s.inv().as_mont();
let u1 = s_inv.mont_mul(&e.as_mont()).demont();
let u2 = s_inv.mont_mul(&r.as_mont()).demont();
let lhs = JacobianMontPoint::public_base_multiply(&u1);
let rhs = JacobianMontPoint::public_multiply_w5(&u2, &self.precomp_w5);
let point = JacobianMontPoint::public_add(&lhs, &rhs);
if point.public_is_infinity() {
return Err(Error::BadSignature);
}
match point.public_x_is(r) {
true => Ok(()),
false => Err(Error::BadSignature),
}
}
}
pub(crate) struct PrivateKey {
scalar: Scalar,
}
impl PrivateKey {
pub(crate) fn new_random() -> Result<Self, Error> {
Self::generate(&mut SystemRandom)
}
pub(crate) fn public_key_uncompressed(&self) -> [u8; PublicKey::BYTES] {
let _entry = low::Entry::new_secret();
self.public_point().as_bytes_uncompressed()
}
pub(crate) fn diffie_hellman(&self, peer: &PublicKey) -> Result<SharedSecret, Error> {
let _entry = low::Entry::new_secret();
let mut shared_point = JacobianMontPoint::multiply(&self.scalar, &peer.point);
let result = shared_point.as_affine();
low::zeroise(&mut shared_point.xyz);
match low::ct::into_public(result.on_curve()) {
true => Ok(SharedSecret(util::u64x4_to_big_endian(
&result.x().demont().0,
))),
false => Err(Error::Fault),
}
}
fn public_point(&self) -> AffineMontPoint {
let point = low::ct::into_public(AffineMontPoint::base_multiply(&self.scalar));
match point.on_curve() {
true => point,
false => panic!("internal fault"),
}
}
pub(crate) fn generate(rng: &mut dyn RandomSource) -> Result<Self, Error> {
let _entry = low::Entry::new_secret();
for _ in 0..64 {
let mut r = [0u8; Scalar::BYTES];
rng.fill(&mut r)?;
low::ct::secret_slice(&r);
if let Ok(p) = Self::from_bytes(&r) {
return Ok(p);
}
}
Err(Error::RngFailed)
}
fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
Scalar::from_bytes_checked(bytes).map(|scalar| Self {
scalar: low::ct::into_secret(scalar),
})
}
}
impl fmt::Debug for PrivateKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PrivateKey").finish_non_exhaustive()
}
}
pub(crate) struct StaticPrivateKey(PrivateKey);
impl StaticPrivateKey {
#[cfg(test)]
pub(crate) fn new_random() -> Result<Self, Error> {
PrivateKey::generate(&mut SystemRandom).map(Self)
}
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
let _entry = low::Entry::new_secret();
PrivateKey::from_bytes(bytes).map(Self)
}
pub(crate) fn secret_bytes(&self) -> [u8; Scalar::BYTES] {
self.0.scalar.as_bytes()
}
pub(crate) fn public_key_uncompressed(&self) -> [u8; PublicKey::BYTES] {
let _entry = low::Entry::new_secret();
self.0.public_point().as_bytes_uncompressed()
}
#[cfg(test)]
pub(crate) fn diffie_hellman(&self, peer: &PublicKey) -> Result<SharedSecret, Error> {
let _entry = low::Entry::new_secret();
self.0.diffie_hellman(peer)
}
pub(crate) fn generate(rng: &mut dyn RandomSource) -> Result<Self, Error> {
let _entry = low::Entry::new_secret();
PrivateKey::generate(rng).map(Self)
}
pub(crate) fn public_key_x_scalar(&self) -> Scalar {
let _entry = low::Entry::new_secret();
self.0.public_point().x_scalar()
}
pub(crate) fn raw_ecdsa_sign(&self, k: &Self, e: &Scalar, r: &Scalar) -> Scalar {
let lhs_mont = self
.0
.scalar
.as_mont()
.mont_mul(&r.as_mont())
.demont()
.add(e)
.as_mont();
low::ct::into_public(k.0.scalar.inv().mont_mul(&lhs_mont))
}
}
pub(crate) struct SharedSecret(pub(crate) [u8; FieldElement::BYTES]);
impl Drop for SharedSecret {
fn drop(&mut self) {
low::zeroise(&mut self.0);
}
}
#[derive(Clone, Copy, Debug, Default)]
struct AffineMontPoint {
xy: [u64; 8],
}
impl AffineMontPoint {
const X: Range<usize> = 0..4;
const Y: Range<usize> = 4..8;
fn from_x962_uncompressed(bytes: &[u8]) -> Result<Self, Error> {
match bytes.first() {
Some(&0x04) => (),
Some(_) => return Err(KeyFormatError::Compressed.into()),
None => return Err(KeyFormatError::WrongLength.into()),
}
if bytes.len() != PublicKey::BYTES {
return Err(KeyFormatError::WrongLength.into());
}
let (_, xy) = bytes.split_at(1);
let (x, y) = xy.split_at(FieldElement::BYTES);
let x = util::big_endian_slice_to_u64x4(x).unwrap();
let y = util::big_endian_slice_to_u64x4(y).unwrap();
let below_p = |v: &[u64; 4]| v.iter().rev().lt(CURVE_PRIME.iter().rev());
if !below_p(&x) || !below_p(&y) {
return Err(KeyFormatError::NotOnCurve.into());
}
let point = Self::from_xy(FieldElement(x).as_mont(), FieldElement(y).as_mont());
if !point.on_curve() {
return Err(KeyFormatError::NotOnCurve.into());
}
Ok(point)
}
fn x_scalar(&self) -> Scalar {
let bytes = self.as_bytes_uncompressed();
Scalar::from_bytes_reduced(&bytes[1..1 + Scalar::BYTES]).unwrap()
}
fn from_xy(x: FieldElement, y: FieldElement) -> Self {
let mut r = Self::default();
r.xy[Self::X].copy_from_slice(&x.0[..]);
r.xy[Self::Y].copy_from_slice(&y.0[..]);
r
}
fn x(&self) -> FieldElement {
FieldElement(self.xy[Self::X].try_into().unwrap())
}
fn y(&self) -> FieldElement {
FieldElement(self.xy[Self::Y].try_into().unwrap())
}
fn on_curve(&self) -> bool {
let x = self.x();
let rhs = x.mont_sqr(); let rhs = rhs.add(&CURVE_A_MONT); let rhs = rhs.mont_mul(&x); let rhs = rhs.add(&CURVE_B_MONT);
let lhs = self.y().mont_sqr();
low::bignum_eq(&lhs.0, &rhs.0)
}
fn as_bytes_uncompressed(&self) -> [u8; PublicKey::BYTES] {
let mut r = [0u8; PublicKey::BYTES];
let (indicator, xy) = r.split_at_mut(1);
let (x, y) = xy.split_at_mut(FieldElement::BYTES);
indicator[0] = 0x04;
x.copy_from_slice(&util::u64x4_to_big_endian(&self.x().demont().0));
y.copy_from_slice(&util::u64x4_to_big_endian(&self.y().demont().0));
r
}
#[cfg(test)]
fn slow_multiply(&self, scalar: &Scalar) -> Self {
let mut result = JacobianMontPoint::infinity();
let mut j = JacobianMontPoint::from_affine(self);
let zero = JacobianMontPoint::zero();
for bit in scalar.bits() {
result.add_inplace(&JacobianMontPoint::select(&zero, &j, bit));
j = j.double();
}
result.as_affine()
}
fn negate_y(&mut self) {
let neg_y = self.y().negate_mod_p();
self.xy[Self::Y].copy_from_slice(&neg_y.0);
}
fn public_precomp_w5(&self) -> JacobianMontPointTableW5 {
let mut r = [JacobianMontPoint::zero(); 16];
macro_rules! index {
($i:literal) => {
$i - 1
};
}
r[index!(1)] = JacobianMontPoint::from_affine(self);
r[index!(2)] = r[index!(1)].double();
r[index!(3)] = r[index!(1)].add(&r[index!(2)]);
r[index!(4)] = r[index!(2)].double();
r[index!(5)] = r[index!(1)].add(&r[index!(4)]);
r[index!(6)] = r[index!(3)].double();
r[index!(7)] = r[index!(1)].add(&r[index!(6)]);
r[index!(8)] = r[index!(4)].double();
r[index!(9)] = r[index!(1)].add(&r[index!(8)]);
r[index!(10)] = r[index!(5)].double();
r[index!(11)] = r[index!(1)].add(&r[index!(10)]);
r[index!(12)] = r[index!(6)].double();
r[index!(13)] = r[index!(1)].add(&r[index!(12)]);
r[index!(14)] = r[index!(7)].double();
r[index!(15)] = r[index!(1)].add(&r[index!(14)]);
r[index!(16)] = r[index!(8)].double();
let mut t = [0; 192];
let (chunks, _) = t.as_chunks_mut::<12>();
for (out, rr) in chunks.iter_mut().zip(r) {
out.copy_from_slice(&rr.xyz);
}
t
}
fn base_multiply(scalar: &Scalar) -> Self {
let mut xy = [0; 8];
low::p256_scalarmulbase(&mut xy, &scalar.0, &precomp::CURVE_GENERATOR_PRECOMP_W6);
let x = FieldElement(xy[Self::X].try_into().unwrap());
let y = FieldElement(xy[Self::Y].try_into().unwrap());
Self::from_xy(x.as_mont(), y.as_mont())
}
fn public_lookup_w6(table: &[u64; 256], index: u8) -> Self {
Self {
xy: table.as_chunks::<8>().0[index as usize - 1],
}
}
}
#[derive(Clone, Copy, Debug)]
struct JacobianMontPoint {
xyz: [u64; 12],
}
impl JacobianMontPoint {
const X: Range<usize> = 0..4;
const Y: Range<usize> = 4..8;
const XY: Range<usize> = 0..8;
const Z: Range<usize> = 8..12;
fn infinity() -> Self {
Self {
xyz: [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
}
}
fn public_is_infinity(&self) -> bool {
self.z().public_eq(&FieldElement::default())
}
fn zero() -> Self {
Self { xyz: [0; 12] }
}
fn x(&self) -> FieldElement {
FieldElement(self.xyz[Self::X].try_into().unwrap())
}
fn y(&self) -> FieldElement {
FieldElement(self.xyz[Self::Y].try_into().unwrap())
}
fn z(&self) -> FieldElement {
FieldElement(self.xyz[Self::Z].try_into().unwrap())
}
fn multiply(scalar: &Scalar, point: &AffineMontPoint) -> Self {
let mut r = Self::zero();
low::p256_montjscalarmul(&mut r.xyz, &scalar.0, &Self::from_affine(point).xyz);
r
}
fn public_base_multiply(scalar: &Scalar) -> Self {
let mut result = Self::infinity();
for (row, (digit, sign)) in precomp::CURVE_GENERATOR_PRECOMP_W6
.iter()
.zip(scalar.booth_recoded_w6())
{
if digit > 0 {
let mut tmp = AffineMontPoint::public_lookup_w6(row, digit);
if sign > 0 {
tmp.negate_y();
}
result.add_inplace_affine(&tmp);
}
}
result
}
fn public_multiply_w5(scalar: &Scalar, precomp: &JacobianMontPointTableW5) -> Self {
let mut terms = scalar.reversed_booth_recoded_w5();
let (digit, _, _) = terms.next().unwrap();
let mut result = Self::public_lookup_w5(precomp, digit);
result.double_inplace_n(5);
for (digit, sign, last) in terms {
let mut tmp = Self::public_lookup_w5(precomp, digit);
if sign > 0 {
tmp.negate_y();
}
result.add_inplace(&tmp);
if !last {
result.double_inplace_n(5);
}
}
result
}
fn from_affine(p: &AffineMontPoint) -> Self {
let mut xyz: [u64; 12] = Default::default();
xyz[Self::XY].copy_from_slice(&p.xy);
xyz[Self::Z].copy_from_slice(&CURVE_ONE_MONT.0);
Self { xyz }
}
fn as_affine(&self) -> AffineMontPoint {
let z2 = self.z().mont_sqr();
let z3 = self.z().mont_mul(&z2);
let z2_inv = z2.demont().inv().as_mont();
let z3_inv = z3.demont().inv().as_mont();
let x = self.x().mont_mul(&z2_inv);
let y = self.y().mont_mul(&z3_inv);
AffineMontPoint::from_xy(x, y)
}
fn public_add(a: &Self, b: &Self) -> Self {
if a.public_is_infinity() {
return *b;
}
if b.public_is_infinity() {
return *a;
}
let (az2, bz2) = (a.z().mont_sqr(), b.z().mont_sqr());
let same_x = a.x().mont_mul(&bz2).public_eq(&b.x().mont_mul(&az2));
if !same_x {
return a.add(b);
}
let ay = a.y().mont_mul(&bz2.mont_mul(&b.z()));
let by = b.y().mont_mul(&az2.mont_mul(&a.z()));
match ay.public_eq(&by) {
true => a.double(),
false => Self::infinity(),
}
}
fn public_x_is(&self, r: &Scalar) -> bool {
let z2 = self.z().mont_sqr();
let is = |x: [u64; 4]| FieldElement(x).as_mont().mont_mul(&z2).public_eq(&self.x());
if is(r.0) {
return true;
}
let mut r_plus_n = [0; 4];
let mut carry = false;
for (sum, (r, n)) in r_plus_n.iter_mut().zip(r.0.iter().zip(CURVE_ORDER)) {
let (s, c1) = r.overflowing_add(n);
let (s, c2) = s.overflowing_add(u64::from(carry));
*sum = s;
carry = c1 | c2;
}
!carry && r_plus_n.iter().rev().lt(CURVE_PRIME.iter().rev()) && is(r_plus_n)
}
#[must_use]
fn double(&self) -> Self {
let mut tmp = Self::zero();
low::p256_montjdouble(&mut tmp.xyz, &self.xyz);
tmp
}
fn double_inplace_n(&mut self, n: usize) {
for _ in 0..n {
let tmp = *self;
low::p256_montjdouble(&mut self.xyz, &tmp.xyz);
}
}
fn add_inplace(&mut self, p: &Self) {
let mut r = Self::infinity();
low::p256_montjadd(&mut r.xyz, &self.xyz, &p.xyz);
*self = r;
}
fn add_inplace_affine(&mut self, p: &AffineMontPoint) {
let mut r = Self::infinity();
low::p256_montjmixadd(&mut r.xyz, &self.xyz, &p.xy);
*self = r;
}
#[must_use]
fn add(&self, p: &Self) -> Self {
let mut r = Self::infinity();
low::p256_montjadd(&mut r.xyz, &self.xyz, &p.xyz);
r
}
#[cfg(test)]
#[must_use]
fn select(p0: &Self, p1: &Self, select: u8) -> Self {
let mut r = Self::zero();
let select = select as u64;
low::bignum_mux(select, &mut r.xyz[..], &p1.xyz[..], &p0.xyz[..]);
r
}
fn public_lookup_w5(table: &JacobianMontPointTableW5, index: u8) -> Self {
let mut r = Self::infinity();
if index > 0 {
let offs = (index as usize - 1) * 12;
r.xyz.copy_from_slice(&table[offs..offs + 12]);
}
r
}
fn negate_y(&mut self) {
let neg_y = self.y().negate_mod_p();
self.xyz[Self::Y].copy_from_slice(&neg_y.0);
}
}
#[derive(Clone, Copy, Debug, Default)]
struct FieldElement([u64; 4]);
impl FieldElement {
const BYTES: usize = 32;
fn inv(&self) -> Self {
let mut r = Self::default();
low::bignum_inv_p256(&mut r.0, &self.0);
r
}
fn mont_sqr(&self) -> Self {
let mut r = Self::default();
low::bignum_montsqr_p256(&mut r.0, &self.0);
r
}
fn add(&self, other: &Self) -> Self {
let mut r = Self::default();
low::bignum_add_p256(&mut r.0, &self.0, &other.0);
r
}
fn mont_mul(&self, other: &Self) -> Self {
let mut r = Self::default();
low::bignum_montmul_p256(&mut r.0, &self.0, &other.0);
r
}
fn demont(&self) -> Self {
let mut r = Self::default();
low::bignum_demont_p256(&mut r.0, &self.0);
r
}
fn as_mont(&self) -> Self {
let mut r = Self::default();
low::bignum_tomont_p256(&mut r.0, &self.0);
r
}
fn negate_mod_p(&self) -> Self {
let mut r = Self::default();
low::bignum_neg_p256(&mut r.0, &self.0);
r
}
fn public_eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
#[derive(Default)]
pub(crate) struct Scalar([u64; 4]);
impl Scalar {
pub(crate) const BYTES: usize = 32;
pub(crate) fn from_bytes_checked(bytes: &[u8]) -> Result<Self, Error> {
let full = Self(
util::big_endian_slice_any_size_to_u64x4(bytes)
.ok_or(KeyFormatError::ScalarOutOfRange)?,
);
full.into_range_check()
}
pub(crate) fn from_bytes_reduced(bytes: &[u8]) -> Result<Self, Error> {
Ok(
Self(util::big_endian_slice_any_size_to_u64x4(bytes).ok_or(Error::WrongLength)?)
.reduce_mod_n(),
)
}
fn into_range_check(self) -> Result<Self, Error> {
let reduced = self.reduce_mod_n();
match low::ct::into_public(reduced.private_eq(&self) & !self.is_zero()) {
true => Ok(self),
false => Err(KeyFormatError::ScalarOutOfRange.into()),
}
}
pub(crate) fn as_bytes(&self) -> [u8; Self::BYTES] {
util::u64x4_to_big_endian(&self.0)
}
#[cfg(test)]
fn small_u64(v: u64) -> Self {
Self([v, 0, 0, 0])
}
pub(crate) fn is_zero(&self) -> bool {
self.private_eq(&Self::default())
}
fn private_eq(&self, other: &Self) -> bool {
low::bignum_eq(&self.0, &other.0)
}
fn reduce_mod_n(&self) -> Self {
let mut r = Self::default();
low::bignum_mod_n256(&mut r.0, &self.0);
r
}
fn demont(&self) -> Self {
let mut r = Self::default();
low::bignum_demont(&mut r.0, &self.0, &CURVE_ORDER);
r
}
fn as_mont(&self) -> Self {
let mut r = Self::default();
low::bignum_montmul(&mut r.0, &self.0, &CURVE_ORDER_MM, &CURVE_ORDER);
r
}
#[cfg(test)]
fn montifier() -> Self {
let mut r = Self::default();
let mut tmp = Self::default();
low::bignum_montifier(&mut r.0, &CURVE_ORDER, &mut tmp.0);
r
}
fn mont_mul(&self, other: &Self) -> Self {
let mut r = Self::default();
low::bignum_montmul(&mut r.0, &self.0, &other.0, &CURVE_ORDER);
r
}
fn inv(&self) -> Self {
let mut r = Self::default();
let mut temp = [0u64; 4 * 3];
low::bignum_modinv(&mut r.0, &self.0, &CURVE_ORDER, &mut temp);
r
}
fn add(&self, other: &Self) -> Self {
let mut r = Self::default();
low::bignum_modadd(&mut r.0, &self.0, &other.0, &CURVE_ORDER);
r
}
#[cfg(test)]
fn bits(&self) -> Bits<'_> {
Bits {
scalar: self,
word: 0,
bit: 0,
}
}
fn booth_recoded_w6(&self) -> BoothRecodeW6 {
BoothRecodeW6::new(self)
}
fn reversed_booth_recoded_w5(&self) -> BoothRecodeW5 {
BoothRecodeW5::new(self)
}
}
impl Drop for Scalar {
fn drop(&mut self) {
low::zeroise(&mut self.0);
}
}
#[cfg(test)]
struct Bits<'a> {
scalar: &'a Scalar,
word: usize,
bit: usize,
}
#[cfg(test)]
impl Iterator for Bits<'_> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if self.word > 3 {
return None;
}
let v = (self.scalar.0[self.word] >> self.bit) & 1;
self.bit += 1;
if self.bit == 64 {
self.word += 1;
self.bit = 0;
}
Some(v as u8)
}
}
struct BoothRecodeW6 {
bytes: [u8; 33],
index: usize,
}
impl BoothRecodeW6 {
fn new(scalar: &Scalar) -> Self {
let mut bytes = [0u8; 33];
bytes[0..8].copy_from_slice(&scalar.0[0].to_le_bytes());
bytes[8..16].copy_from_slice(&scalar.0[1].to_le_bytes());
bytes[16..24].copy_from_slice(&scalar.0[2].to_le_bytes());
bytes[24..32].copy_from_slice(&scalar.0[3].to_le_bytes());
Self { bytes, index: 0 }
}
fn recode(v: u8) -> (u8, u8) {
let sign = !((v >> 6).wrapping_sub(1));
let d = (1u16 << 7).wrapping_sub(v as u16).wrapping_sub(1) as u8;
let d = (d & sign) | (v & !sign);
let d = (d >> 1).wrapping_add(d & 1);
(d, sign & 1)
}
}
impl Iterator for BoothRecodeW6 {
type Item = (u8, u8);
fn next(&mut self) -> Option<Self::Item> {
const MASK: u8 = (1 << (6 + 1)) - 1;
match self.index {
0 => {
self.index += 6;
Some(Self::recode((self.bytes[0] << 1) & MASK))
}
6..=252 => {
let offset = (self.index - 1) / 8;
let shift = (self.index - 1) % 8;
let value = (((self.bytes[offset] as u16) | ((self.bytes[offset + 1] as u16) << 8))
>> shift) as u8
& MASK;
self.index += 6;
Some(Self::recode(value))
}
_ => None,
}
}
}
struct BoothRecodeW5 {
bytes: [u8; 33],
index: usize,
}
impl BoothRecodeW5 {
fn new(scalar: &Scalar) -> Self {
let mut bytes = [0u8; 33];
bytes[0..8].copy_from_slice(&scalar.0[0].to_le_bytes());
bytes[8..16].copy_from_slice(&scalar.0[1].to_le_bytes());
bytes[16..24].copy_from_slice(&scalar.0[2].to_le_bytes());
bytes[24..32].copy_from_slice(&scalar.0[3].to_le_bytes());
Self { bytes, index: 255 }
}
fn recode(v: u8) -> (u8, u8) {
let sign = !((v >> 5).wrapping_sub(1));
let d = (1u16 << 6).wrapping_sub(v as u16).wrapping_sub(1) as u8;
let d = (d & sign) | (v & !sign);
let d = (d >> 1).wrapping_add(d & 1);
(d, sign & 1)
}
}
impl Iterator for BoothRecodeW5 {
type Item = (u8, u8, bool);
fn next(&mut self) -> Option<Self::Item> {
const MASK: u8 = (1 << (5 + 1)) - 1;
match self.index {
5..=255 => {
let offset = (self.index - 1) / 8;
let shift = (self.index - 1) % 8;
let value = (((self.bytes[offset] as u16) | ((self.bytes[offset + 1] as u16) << 8))
>> shift) as u8
& MASK;
let (digit, sign) = Self::recode(value);
self.index -= 5;
Some((digit, sign, false))
}
0 => {
let value = (self.bytes[0] << 1) & MASK;
let (digit, sign) = Self::recode(value);
self.index = usize::MAX;
Some((digit, sign, true))
}
_ => None,
}
}
}
type AffineMontPointTableW6 = [[u64; 256]; 43];
type JacobianMontPointTableW5 = [u64; 192];
const CURVE_A_MONT: FieldElement = FieldElement([
0xffff_ffff_ffff_fffc,
0x0000_0003_ffff_ffff,
0x0000_0000_0000_0000,
0xffff_fffc_0000_0004,
]);
const CURVE_B_MONT: FieldElement = FieldElement([
0xd89c_df62_29c4_bddf,
0xacf0_05cd_7884_3090,
0xe5a2_20ab_f721_2ed6,
0xdc30_061d_0487_4834,
]);
const CURVE_ONE_MONT: FieldElement = FieldElement([
0x0000_0000_0000_0001,
0xffff_ffff_0000_0000,
0xffff_ffff_ffff_ffff,
0x0000_0000_ffff_fffe,
]);
const CURVE_PRIME: [u64; 4] = [
0xffff_ffff_ffff_ffff,
0x0000_0000_ffff_ffff,
0x0000_0000_0000_0000,
0xffff_ffff_0000_0001,
];
const CURVE_ORDER: [u64; 4] = [
0xf3b9_cac2_fc63_2551,
0xbce6_faad_a717_9e84,
0xffff_ffff_ffff_ffff,
0xffff_ffff_0000_0000,
];
const CURVE_ORDER_MM: [u64; 4] = [
0x83244c95be79eea2,
0x4699799c49bd6fa6,
0x2845b2392b6bec59,
0x66e12d94f3d95620,
];
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
const CURVE_GENERATOR: AffineMontPoint = AffineMontPoint {
xy: [
0x79e7_30d4_18a9_143c,
0x75ba_95fc_5fed_b601,
0x79fb_732b_7762_2510,
0x1890_5f76_a537_55c6,
0xddf2_5357_ce95_560a,
0x8b4a_b8e4_ba19_e45c,
0xd2e8_8688_dd21_f325,
0x8571_ff18_2588_5d85,
],
};
#[test]
fn generator_on_curve() {
println!("{CURVE_GENERATOR:x?}");
assert!(CURVE_GENERATOR.on_curve());
println!("demont {:x?}", CURVE_GENERATOR.as_bytes_uncompressed());
}
#[test]
fn generate_key_1() {
let scalar = Scalar::small_u64(1);
let r = CURVE_GENERATOR.slow_multiply(&scalar);
assert_eq!(
r.as_bytes_uncompressed(),
CURVE_GENERATOR.as_bytes_uncompressed()
);
println!("raw {r:x?}");
println!("fmt {:x?}", r.as_bytes_uncompressed());
}
#[test]
fn point_double() {
let mut p = JacobianMontPoint::from_affine(&CURVE_GENERATOR);
println!("p = {p:x?}");
p = p.double();
println!("p2 = {p:x?}");
println!("p2 aff = {:x?}", p.as_affine());
println!("enc = {:x?}", p.as_affine().as_bytes_uncompressed());
}
#[test]
fn generate_key_2() {
let scalar = Scalar::small_u64(2);
let r = CURVE_GENERATOR.slow_multiply(&scalar);
println!("raw {r:x?}");
println!("fmt {:x?}", r.as_bytes_uncompressed());
}
#[test]
fn multiply_matches_double_and_add() {
let n_minus = |k: u64| {
let mut s = CURVE_ORDER;
s[0] -= k;
Scalar(s)
};
let all_32 = Scalar([0x0820_8208_2082_0820; 4]);
for scalar in [
Scalar::small_u64(1),
Scalar::small_u64(2),
Scalar::small_u64(3),
Scalar::small_u64(32),
Scalar::small_u64(33),
Scalar::small_u64(99999999),
Scalar([0, 0, 0, 1 << 63]),
all_32,
n_minus(1),
n_minus(2),
] {
let expected = CURVE_GENERATOR.slow_multiply(&scalar).xy;
assert_eq!(AffineMontPoint::base_multiply(&scalar).xy, expected);
assert_eq!(
JacobianMontPoint::public_base_multiply(&scalar)
.as_affine()
.xy,
expected
);
assert_eq!(
JacobianMontPoint::multiply(&scalar, &CURVE_GENERATOR)
.as_affine()
.xy,
expected
);
let precomp = CURVE_GENERATOR.public_precomp_w5();
assert_eq!(
JacobianMontPoint::public_multiply_w5(&scalar, &precomp)
.as_affine()
.xy,
expected
);
}
}
#[test]
fn generate_key_known_answer() {
let bytes = b"\x1F\x55\x45\x23\x08\x50\x8C\x6B\x24\x37\x0F\x22\x1E\xF1\xB3\xF9\x54\x46\xBE\x4F\x8A\x4B\x42\x8A\x5B\x51\xB7\x10\xC2\x68\x4C\x03";
let private = PrivateKey::from_bytes(bytes).unwrap();
println!("priv = {private:x?}");
let public = private.public_key_uncompressed();
println!("pub = {public:x?}");
const EXPECTED: &[u8; 65] = b"\x04\xcb\x8a\x14\x1c\xd7\xe4\x07\xaf\x69\xa5\x01\x88\xe9\x1c\xe5\x5d\xcc\xfd\x33\x48\xda\xba\x4a\x9c\x46\x64\x33\x2e\x95\x59\xb6\x81\x44\xfc\x1a\x61\xd8\x41\xe4\xdb\x80\x1b\x33\x51\x20\x12\x1d\x0b\xa4\x84\xb3\xc9\x53\xb3\x1d\x35\x1d\x7f\xa2\x13\x97\xd1\x25\x47";
assert_eq!(&public, EXPECTED);
PublicKey::from_x962_uncompressed(&public).unwrap();
}
#[test]
fn test_raw_ecdsa_sign() {
let private = StaticPrivateKey::from_bytes(b"\xd1\xf6\xbc\xcc\x3e\x5a\x40\x1b\xcc\x2c\x21\xbe\x34\x90\xed\x38\xde\xf4\x93\x7f\x78\x06\x03\xf5\x2b\x23\xb9\xa6\xfa\x9c\xf6\x0e").unwrap();
let k = StaticPrivateKey::from_bytes(b"\xe7\x95\x37\xa1\xd7\x55\x45\x1f\x8c\x3c\xbf\xf7\x84\xea\x5c\x1c\xdf\xe1\x6b\x1d\x13\xe7\xbf\xbb\x04\xd7\xfd\x90\x57\xee\xee\xf7").unwrap();
let e = Scalar::from_bytes_checked(b"\x2c\xf2\x4d\xba\x5f\xb0\xa3\x0e\x26\xe8\x3b\x2a\xc5\xb9\xe2\x9e\x1b\x16\x1e\x5c\x1f\xa7\x42\x5e\x73\x04\x33\x62\x93\x8b\x98\x24").unwrap();
let r = Scalar::from_bytes_checked(b"\x78\xee\x34\xc8\xb6\x52\x29\x54\x96\x19\x79\x45\x2e\x6e\x0c\xe0\x68\x5d\x40\x42\x38\x41\xef\xeb\x06\xfe\x3e\x3f\xf7\xb6\x5d\xf5").unwrap();
let s = private.raw_ecdsa_sign(&k, &e, &r);
assert_eq!(
format!("{:02x?}", s.as_bytes()),
"[5b, c9, 8e, 7d, 28, 74, d0, 9d, e8, fb, da, 22, 34, 83, 24, 4f, a1, ba, a2, 6a, 71, 91, 4e, 8e, d4, 8f, 88, b8, 2d, 17, 0b, 4b]"
);
}
#[test]
fn private_key_in_range() {
assert_eq!(
PrivateKey::from_bytes(&[0u8; 32]).unwrap_err(),
Error::from(KeyFormatError::ScalarOutOfRange)
);
assert_eq!(PrivateKey::from_bytes(b"\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xbc\xe6\xfa\xad\xa7\x17\x9e\x84\xf3\xb9\xca\xc2\xfc\x63\x25\x51").unwrap_err(), Error::from(KeyFormatError::ScalarOutOfRange));
assert_eq!(PrivateKey::from_bytes(b"\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xbc\xe6\xfa\xad\xa7\x17\x9e\x84\xf3\xb9\xca\xc2\xfc\x63\x25\x52").unwrap_err(), Error::from(KeyFormatError::ScalarOutOfRange));
PrivateKey::from_bytes(b"\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xbc\xe6\xfa\xad\xa7\x17\x9e\x84\xf3\xb9\xca\xc2\xfc\x63\x25\x50").unwrap();
}
#[test]
fn curve_field_elements_as_mont() {
const CURVE_A: FieldElement = FieldElement([
0xffff_ffff_ffff_fffc,
0x0000_0000_ffff_ffff,
0x0000_0000_0000_0000,
0xffff_ffff_0000_0001,
]);
const CURVE_B: FieldElement = FieldElement([
0x3bce_3c3e_27d2_604b,
0x651d_06b0_cc53_b0f6,
0xb3eb_bd55_7698_86bc,
0x5ac6_35d8_aa3a_93e7,
]);
println!("G.x = {:x?}", CURVE_GENERATOR.x().as_mont());
println!("G.y = {:x?}", CURVE_GENERATOR.y().as_mont());
println!("a = {:x?}", CURVE_A.as_mont());
println!("b = {:x?}", CURVE_B.as_mont());
let one = FieldElement([1, 0, 0, 0]);
println!("R = {:x?}", one.as_mont());
println!("R * R = {:x?}", one.as_mont().as_mont());
println!("montify n = {:016x?}", Scalar::montifier().0);
}
#[test]
fn base_point_precomp_w6() {
let mut base = JacobianMontPoint::from_affine(&CURVE_GENERATOR);
for row in &precomp::CURVE_GENERATOR_PRECOMP_W6 {
let mut multiple = base;
for (i, entry) in (1..).zip(row.as_chunks::<8>().0) {
assert_eq!(&multiple.as_affine().xy, entry);
multiple = match i {
1 => multiple.double(),
_ => multiple.add(&base),
};
}
base.double_inplace_n(6);
}
}
}