chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

68
vendor/p521/src/arithmetic.rs vendored Normal file
View File

@@ -0,0 +1,68 @@
//! Pure Rust implementation of group operations on secp521r1.
//!
//! Curve parameters can be found in [NIST SP 800-186] § 3.2.1.5: P-521.
//!
//! [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final
pub(crate) mod field;
#[cfg(feature = "hash2curve")]
mod hash2curve;
pub(crate) mod scalar;
mod util;
pub use self::scalar::Scalar;
use self::field::FieldElement;
use crate::NistP521;
use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic};
use primeorder::{point_arithmetic, PrimeCurveParams};
/// Elliptic curve point in affine coordinates.
pub type AffinePoint = primeorder::AffinePoint<NistP521>;
/// Elliptic curve point in projective coordinates.
pub type ProjectivePoint = primeorder::ProjectivePoint<NistP521>;
impl CurveArithmetic for NistP521 {
type AffinePoint = AffinePoint;
type ProjectivePoint = ProjectivePoint;
type Scalar = Scalar;
}
impl PrimeCurveArithmetic for NistP521 {
type CurveGroup = ProjectivePoint;
}
/// Adapted from [NIST SP 800-186] § 3.2.1.5: P-521.
///
/// [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final
impl PrimeCurveParams for NistP521 {
type FieldElement = FieldElement;
type PointArithmetic = point_arithmetic::EquationAIsMinusThree;
/// a = -3 (0x1ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
/// ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
/// ffffffff ffffffff ffffffff fffffffc)
const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg();
/// b = 0x051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b 99b315f3
/// b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd 3bb1bf07
/// 3573df88 3d2c34f1 ef451fd4 6b503f00
const EQUATION_B: FieldElement =
FieldElement::from_hex("0000000000000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00");
/// Base point of P-521.
///
/// ```text
/// Gₓ = 0x0c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 053fb521
/// f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 a2ffa8de
/// 3348b3c1 856a429b f97e7e31 c2e5bd66
/// Gᵧ = 0x118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 579b4468
/// 17afbd17 273e662c 97ee7299 5ef42640 c550b901 3fad0761
/// 353c7086 a272c240 88be9476 9fd16650
/// ```
const GENERATOR: (FieldElement, FieldElement) = (
FieldElement::from_hex("00000000000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66"),
FieldElement::from_hex("000000000000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"),
);
}

664
vendor/p521/src/arithmetic/field.rs vendored Normal file
View File

@@ -0,0 +1,664 @@
//! Field arithmetic modulo p = 2^{521} 1
//!
//! Arithmetic implementations have been synthesized using fiat-crypto.
//!
//! # License
//!
//! Copyright (c) 2015-2020 the fiat-crypto authors
//!
//! fiat-crypto is distributed under the terms of the MIT License, the
//! Apache License (Version 2.0), and the BSD 1-Clause License;
//! users may pick which license to apply.
#![allow(
clippy::should_implement_trait,
clippy::suspicious_op_assign_impl,
clippy::unused_unit,
clippy::unnecessary_cast,
clippy::too_many_arguments,
clippy::identity_op,
rustdoc::bare_urls
)]
// TODO(tarcieri): 32-bit backend?
#[path = "field/p521_64.rs"]
mod field_impl;
mod loose;
pub(crate) use self::loose::LooseFieldElement;
use self::field_impl::*;
use crate::{FieldBytes, NistP521, U576};
use core::{
fmt::{self, Debug},
iter::{Product, Sum},
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use elliptic_curve::{
ff::{self, Field, PrimeField},
generic_array::GenericArray,
rand_core::RngCore,
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeLess, CtOption},
zeroize::DefaultIsZeroes,
Error, FieldBytesEncoding,
};
use super::util::u576_to_le_bytes;
/// Constant representing the modulus serialized as hex.
/// p = 2^{521} 1
const MODULUS_HEX: &str = "00000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
pub(crate) const MODULUS: U576 = U576::from_be_hex(MODULUS_HEX);
/// Element of the secp521r1 base field used for curve coordinates.
#[derive(Clone, Copy)]
pub struct FieldElement(pub(crate) fiat_p521_tight_field_element);
impl FieldElement {
/// Zero element.
pub const ZERO: Self = Self::from_u64(0);
/// Multiplicative identity.
pub const ONE: Self = Self::from_u64(1);
/// Number of bytes in the serialized representation.
const BYTES: usize = 66;
/// Create a [`FieldElement`] from a canonical big-endian representation.
pub fn from_bytes(repr: &FieldBytes) -> CtOption<Self> {
let uint = <U576 as FieldBytesEncoding<NistP521>>::decode_field_bytes(repr);
Self::from_uint(uint)
}
/// Decode [`FieldElement`] from a big endian byte slice.
pub fn from_slice(slice: &[u8]) -> elliptic_curve::Result<Self> {
if slice.len() != Self::BYTES {
return Err(Error);
}
Option::from(Self::from_bytes(GenericArray::from_slice(slice))).ok_or(Error)
}
/// Decode [`FieldElement`] from [`U576`].
pub fn from_uint(uint: U576) -> CtOption<Self> {
let is_some = uint.ct_lt(&MODULUS);
CtOption::new(Self::from_uint_unchecked(uint), is_some)
}
/// Parse a [`FieldElement`] from big endian hex-encoded bytes.
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// This method is primarily intended for defining internal constants.
pub(crate) const fn from_hex(hex: &str) -> Self {
Self::from_uint_unchecked(U576::from_be_hex(hex))
}
/// Convert a `u64` into a [`FieldElement`].
pub const fn from_u64(w: u64) -> Self {
Self::from_uint_unchecked(U576::from_u64(w))
}
/// Decode [`FieldElement`] from [`U576`].
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// Used incorrectly this can lead to invalid results!
pub(crate) const fn from_uint_unchecked(w: U576) -> Self {
Self(fiat_p521_from_bytes(&u576_to_le_bytes(w)))
}
/// Returns the big-endian encoding of this [`FieldElement`].
pub fn to_bytes(self) -> FieldBytes {
let mut ret = fiat_p521_to_bytes(&self.0);
ret.reverse();
GenericArray::clone_from_slice(&ret)
}
/// Determine if this [`FieldElement`] is odd in the SEC1 sense: `self mod 2 == 1`.
///
/// # Returns
///
/// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_odd(&self) -> Choice {
Choice::from(self.0[0] as u8 & 1)
}
/// Determine if this [`FieldElement`] is even in the SEC1 sense: `self mod 2 == 0`.
///
/// # Returns
///
/// If even, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_even(&self) -> Choice {
!self.is_odd()
}
/// Determine if this [`FieldElement`] is zero.
///
/// # Returns
///
/// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_zero(&self) -> Choice {
self.ct_eq(&Self::ZERO)
}
/// Add elements.
#[allow(dead_code)] // TODO(tarcieri): currently unused
pub(crate) const fn add_loose(&self, rhs: &Self) -> LooseFieldElement {
LooseFieldElement(fiat_p521_add(&self.0, &rhs.0))
}
/// Double element (add it to itself).
#[allow(dead_code)] // TODO(tarcieri): currently unused
#[must_use]
pub(crate) const fn double_loose(&self) -> LooseFieldElement {
Self::add_loose(self, self)
}
/// Subtract elements, returning a loose field element.
#[allow(dead_code)] // TODO(tarcieri): currently unused
pub(crate) const fn sub_loose(&self, rhs: &Self) -> LooseFieldElement {
LooseFieldElement(fiat_p521_sub(&self.0, &rhs.0))
}
/// Negate element, returning a loose field element.
#[allow(dead_code)] // TODO(tarcieri): currently unused
pub(crate) const fn neg_loose(&self) -> LooseFieldElement {
LooseFieldElement(fiat_p521_opp(&self.0))
}
/// Add two field elements.
pub const fn add(&self, rhs: &Self) -> Self {
Self(fiat_p521_carry_add(&self.0, &rhs.0))
}
/// Subtract field elements.
pub const fn sub(&self, rhs: &Self) -> Self {
Self(fiat_p521_carry_sub(&self.0, &rhs.0))
}
/// Negate element.
pub const fn neg(&self) -> Self {
Self(fiat_p521_carry_opp(&self.0))
}
/// Double element (add it to itself).
#[must_use]
pub const fn double(&self) -> Self {
self.add(self)
}
/// Multiply elements.
pub const fn multiply(&self, rhs: &Self) -> Self {
LooseFieldElement::mul(&self.relax(), &rhs.relax())
}
/// Square element.
pub const fn square(&self) -> Self {
self.relax().square()
}
/// Returns self^(2^n) mod p
const fn sqn(&self, n: usize) -> Self {
let mut x = self.square();
let mut i = 1;
while i < n {
x = x.square();
i += 1;
}
x
}
/// Returns `self^exp`, where `exp` is a little-endian integer exponent.
///
/// **This operation is variable time with respect to the exponent.**
///
/// If the exponent is fixed, this operation is effectively constant time.
pub const fn pow_vartime(&self, exp: &[u64]) -> Self {
let mut res = Self::ONE;
let mut i = exp.len();
while i > 0 {
i -= 1;
let mut j = 64;
while j > 0 {
j -= 1;
res = res.square();
if ((exp[i] >> j) & 1) == 1 {
res = Self::multiply(&res, self);
}
}
}
res
}
/// Compute [`FieldElement`] inversion: `1 / self`.
pub fn invert(&self) -> CtOption<Self> {
CtOption::new(self.invert_unchecked(), !self.is_zero())
}
/// Returns the multiplicative inverse of self.
///
/// Does not check that self is non-zero.
const fn invert_unchecked(&self) -> Self {
// Adapted from addchain: github.com/mmcloughlin/addchain
let z = self.square();
let z = self.multiply(&z);
let t0 = z.sqn(2);
let z = z.multiply(&t0);
let t0 = z.sqn(4);
let z = z.multiply(&t0);
let t0 = z.sqn(8);
let z = z.multiply(&t0);
let t0 = z.sqn(16);
let z = z.multiply(&t0);
let t0 = z.sqn(32);
let z = z.multiply(&t0);
let t0 = z.square();
let t0 = self.multiply(&t0);
let t0 = t0.sqn(64);
let z = z.multiply(&t0);
let t0 = z.square();
let t0 = self.multiply(&t0);
let t0 = t0.sqn(129);
let z = z.multiply(&t0);
let t0 = z.square();
let t0 = self.multiply(&t0);
let t0 = t0.sqn(259);
let z = z.multiply(&t0);
let z = z.sqn(2);
self.multiply(&z)
}
/// Returns the square root of self mod p, or `None` if no square root
/// exists.
///
/// # Implementation details
/// If _x_ has a sqrt, then due to Euler's criterion this implies x<sup>(p - 1)/2</sup> = 1.
/// 1. x<sup>(p + 1)/2</sup> = x.
/// 2. There's a special property due to _p ≡ 3 (mod 4)_ which implies _(p + 1)/4_ is an integer.
/// 3. We can rewrite `1.` as x<sup>((p+1)/4)<sup>2</sup></sup>
/// 4. x<sup>(p+1)/4</sup> is the square root.
/// 5. This is simplified as (2<sup>251</sup> - 1 + 1) /4 = 2<sup>519</sup>
/// 6. Hence, x<sup>2<sup>519</sup></sup> is the square root iff _result.square() == self_
pub fn sqrt(&self) -> CtOption<Self> {
let sqrt = self.sqn(519);
CtOption::new(sqrt, sqrt.square().ct_eq(self))
}
/// Relax a tight field element into a loose one.
pub(crate) const fn relax(&self) -> LooseFieldElement {
LooseFieldElement(fiat_p521_relax(&self.0))
}
}
impl AsRef<fiat_p521_tight_field_element> for FieldElement {
fn as_ref(&self) -> &fiat_p521_tight_field_element {
&self.0
}
}
impl Default for FieldElement {
fn default() -> Self {
Self::ZERO
}
}
impl Debug for FieldElement {
/// Formatting machinery for [`FieldElement`]
///
/// # Why
/// ```ignore
/// let fe1 = FieldElement([9, 0, 0, 0, 0, 0, 0, 0, 0]);
/// let fe2 = FieldElement([
/// 8,
/// 0,
/// 288230376151711744,
/// 288230376151711743,
/// 288230376151711743,
/// 288230376151711743,
/// 288230376151711743,
/// 288230376151711743,
/// 144115188075855871,
/// ]);
/// ```
///
/// For the above example, deriving [`core::fmt::Debug`] will result in returning 2 different
/// strings, which are in reality the same due to p521's unsaturated math, instead print the
/// output as a hex string in big-endian.
///
/// This makes debugging easier.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut bytes = fiat_p521_to_bytes(&self.0);
bytes.reverse();
let formatter = base16ct::HexDisplay(&bytes);
f.debug_tuple("FieldElement")
.field(&format_args!("0x{formatter:X}"))
.finish()
}
}
impl Eq for FieldElement {}
impl PartialEq for FieldElement {
fn eq(&self, rhs: &Self) -> bool {
self.ct_eq(rhs).into()
}
}
impl From<u32> for FieldElement {
fn from(n: u32) -> FieldElement {
Self::from_uint_unchecked(U576::from(n))
}
}
impl From<u64> for FieldElement {
fn from(n: u64) -> FieldElement {
Self::from_uint_unchecked(U576::from(n))
}
}
impl From<u128> for FieldElement {
fn from(n: u128) -> FieldElement {
Self::from_uint_unchecked(U576::from(n))
}
}
impl ConditionallySelectable for FieldElement {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
let mut ret = Self::ZERO;
for i in 0..ret.0.len() {
ret.0[i] = u64::conditional_select(&a.0[i], &b.0[i], choice);
}
ret
}
}
impl ConstantTimeEq for FieldElement {
fn ct_eq(&self, other: &Self) -> Choice {
let a = fiat_p521_to_bytes(&self.0);
let b = fiat_p521_to_bytes(&other.0);
a.ct_eq(&b)
}
}
impl DefaultIsZeroes for FieldElement {}
impl Field for FieldElement {
const ZERO: Self = Self::ZERO;
const ONE: Self = Self::ONE;
fn random(mut rng: impl RngCore) -> Self {
// NOTE: can't use ScalarPrimitive::random due to CryptoRng bound
let mut bytes = <FieldBytes>::default();
loop {
rng.fill_bytes(&mut bytes);
if let Some(fe) = Self::from_bytes(&bytes).into() {
return fe;
}
}
}
fn is_zero(&self) -> Choice {
Self::ZERO.ct_eq(self)
}
#[must_use]
fn square(&self) -> Self {
self.square()
}
#[must_use]
fn double(&self) -> Self {
self.double()
}
fn invert(&self) -> CtOption<Self> {
self.invert()
}
fn sqrt(&self) -> CtOption<Self> {
self.sqrt()
}
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
ff::helpers::sqrt_ratio_generic(num, div)
}
}
impl PrimeField for FieldElement {
type Repr = FieldBytes;
const MODULUS: &'static str = MODULUS_HEX;
const NUM_BITS: u32 = 521;
const CAPACITY: u32 = 520;
const TWO_INV: Self = Self::from_u64(2).invert_unchecked();
const MULTIPLICATIVE_GENERATOR: Self = Self::from_u64(3);
const S: u32 = 1;
const ROOT_OF_UNITY: Self = Self::from_hex("00000000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
const ROOT_OF_UNITY_INV: Self = Self::ROOT_OF_UNITY.invert_unchecked();
const DELTA: Self = Self::from_u64(9);
#[inline]
fn from_repr(bytes: FieldBytes) -> CtOption<Self> {
Self::from_bytes(&bytes)
}
#[inline]
fn to_repr(&self) -> FieldBytes {
self.to_bytes()
}
#[inline]
fn is_odd(&self) -> Choice {
self.is_odd()
}
}
//
// `core::ops` impls
//
impl Add for FieldElement {
type Output = FieldElement;
#[inline]
fn add(self, rhs: FieldElement) -> FieldElement {
Self::add(&self, &rhs)
}
}
impl Add<&FieldElement> for FieldElement {
type Output = FieldElement;
#[inline]
fn add(self, rhs: &FieldElement) -> FieldElement {
Self::add(&self, rhs)
}
}
impl Add<&FieldElement> for &FieldElement {
type Output = FieldElement;
#[inline]
fn add(self, rhs: &FieldElement) -> FieldElement {
FieldElement::add(self, rhs)
}
}
impl AddAssign<FieldElement> for FieldElement {
#[inline]
fn add_assign(&mut self, other: FieldElement) {
*self = *self + other;
}
}
impl AddAssign<&FieldElement> for FieldElement {
#[inline]
fn add_assign(&mut self, other: &FieldElement) {
*self = *self + other;
}
}
impl Sub for FieldElement {
type Output = FieldElement;
#[inline]
fn sub(self, rhs: FieldElement) -> FieldElement {
Self::sub(&self, &rhs)
}
}
impl Sub<&FieldElement> for FieldElement {
type Output = FieldElement;
#[inline]
fn sub(self, rhs: &FieldElement) -> FieldElement {
Self::sub(&self, rhs)
}
}
impl Sub<&FieldElement> for &FieldElement {
type Output = FieldElement;
#[inline]
fn sub(self, rhs: &FieldElement) -> FieldElement {
FieldElement::sub(self, rhs)
}
}
impl SubAssign<FieldElement> for FieldElement {
#[inline]
fn sub_assign(&mut self, other: FieldElement) {
*self = *self - other;
}
}
impl SubAssign<&FieldElement> for FieldElement {
#[inline]
fn sub_assign(&mut self, other: &FieldElement) {
*self = *self - other;
}
}
impl Mul for FieldElement {
type Output = FieldElement;
#[inline]
fn mul(self, rhs: FieldElement) -> FieldElement {
self.relax().mul(&rhs.relax())
}
}
impl Mul<&FieldElement> for FieldElement {
type Output = FieldElement;
#[inline]
fn mul(self, rhs: &FieldElement) -> FieldElement {
self.relax().mul(&rhs.relax())
}
}
impl Mul<&FieldElement> for &FieldElement {
type Output = FieldElement;
#[inline]
fn mul(self, rhs: &FieldElement) -> FieldElement {
self.relax().mul(&rhs.relax())
}
}
impl MulAssign<&FieldElement> for FieldElement {
#[inline]
fn mul_assign(&mut self, other: &FieldElement) {
*self = *self * other;
}
}
impl MulAssign for FieldElement {
#[inline]
fn mul_assign(&mut self, other: FieldElement) {
*self = *self * other;
}
}
impl Neg for FieldElement {
type Output = FieldElement;
#[inline]
fn neg(self) -> FieldElement {
Self::neg(&self)
}
}
//
// `core::iter` trait impls
//
impl Sum for FieldElement {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO)
}
}
impl<'a> Sum<&'a FieldElement> for FieldElement {
fn sum<I: Iterator<Item = &'a FieldElement>>(iter: I) -> Self {
iter.copied().sum()
}
}
impl Product for FieldElement {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE)
}
}
impl<'a> Product<&'a FieldElement> for FieldElement {
fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
iter.copied().product()
}
}
#[cfg(test)]
mod tests {
use super::FieldElement;
use elliptic_curve::ff::PrimeField;
use hex_literal::hex;
use primeorder::{
impl_field_identity_tests, impl_field_invert_tests, impl_field_sqrt_tests,
impl_primefield_tests,
};
/// t = (modulus - 1) >> S
const T: [u64; 9] = [
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0x00000000000000ff,
];
impl_field_identity_tests!(FieldElement);
impl_field_invert_tests!(FieldElement);
impl_field_sqrt_tests!(FieldElement);
impl_primefield_tests!(FieldElement, T);
/// Regression test for RustCrypto/elliptic-curves#965
#[test]
fn decode_invalid_field_element_returns_err() {
let overflowing_bytes = hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
let ct_option = FieldElement::from_bytes(overflowing_bytes.as_ref().into());
assert!(bool::from(ct_option.is_none()));
}
}

View File

@@ -0,0 +1,77 @@
use super::{field_impl::*, FieldElement};
use core::ops::Mul;
/// "Loose" field element.
pub(crate) struct LooseFieldElement(pub(super) fiat_p521_loose_field_element);
impl LooseFieldElement {
/// Reduce field element.
pub(crate) const fn carry(&self) -> FieldElement {
FieldElement(fiat_p521_carry(&self.0))
}
/// Multiplies two field elements and reduces the result.
pub(crate) const fn mul(&self, rhs: &Self) -> FieldElement {
FieldElement(fiat_p521_carry_mul(&self.0, &rhs.0))
}
/// Squares a field element and reduces the result.
pub(crate) const fn square(&self) -> FieldElement {
FieldElement(fiat_p521_carry_square(&self.0))
}
}
impl From<FieldElement> for LooseFieldElement {
#[inline]
fn from(tight: FieldElement) -> LooseFieldElement {
LooseFieldElement::from(&tight)
}
}
impl From<&FieldElement> for LooseFieldElement {
#[inline]
fn from(tight: &FieldElement) -> LooseFieldElement {
tight.relax()
}
}
impl From<LooseFieldElement> for FieldElement {
#[inline]
fn from(loose: LooseFieldElement) -> FieldElement {
FieldElement::from(&loose)
}
}
impl From<&LooseFieldElement> for FieldElement {
#[inline]
fn from(loose: &LooseFieldElement) -> FieldElement {
loose.carry()
}
}
impl Mul for LooseFieldElement {
type Output = FieldElement;
#[inline]
fn mul(self, rhs: LooseFieldElement) -> FieldElement {
Self::mul(&self, &rhs)
}
}
impl Mul<&LooseFieldElement> for LooseFieldElement {
type Output = FieldElement;
#[inline]
fn mul(self, rhs: &LooseFieldElement) -> FieldElement {
Self::mul(&self, rhs)
}
}
impl Mul<&LooseFieldElement> for &LooseFieldElement {
type Output = FieldElement;
#[inline]
fn mul(self, rhs: &LooseFieldElement) -> FieldElement {
LooseFieldElement::mul(self, rhs)
}
}

File diff suppressed because it is too large Load Diff

367
vendor/p521/src/arithmetic/hash2curve.rs vendored Normal file
View File

@@ -0,0 +1,367 @@
use super::FieldElement;
use crate::{AffinePoint, NistP521, ProjectivePoint, Scalar};
use elliptic_curve::{
bigint::{ArrayEncoding, U576},
consts::U98,
generic_array::GenericArray,
hash2curve::{FromOkm, GroupDigest, MapToCurve, OsswuMap, OsswuMapParams, Sgn0},
ops::Reduce,
point::DecompressPoint,
subtle::Choice,
};
impl GroupDigest for NistP521 {
type FieldElement = FieldElement;
}
impl FromOkm for FieldElement {
type Length = U98;
fn from_okm(data: &GenericArray<u8, Self::Length>) -> Self {
const F_2_392: FieldElement = FieldElement::from_hex(
"000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
);
let mut d0 = GenericArray::default();
d0[23..].copy_from_slice(&data[0..49]);
let d0 = FieldElement::from_uint_unchecked(U576::from_be_byte_array(d0));
let mut d1 = GenericArray::default();
d1[23..].copy_from_slice(&data[49..]);
let d1 = FieldElement::from_uint_unchecked(U576::from_be_byte_array(d1));
d0 * F_2_392 + d1
}
}
impl Sgn0 for FieldElement {
fn sgn0(&self) -> Choice {
self.is_odd()
}
}
impl OsswuMap for FieldElement {
const PARAMS: OsswuMapParams<Self> = OsswuMapParams {
c1: &[
0xffff_ffff_ffff_ffff,
0xffff_ffff_ffff_ffff,
0xffff_ffff_ffff_ffff,
0xffff_ffff_ffff_ffff,
0xffff_ffff_ffff_ffff,
0xffff_ffff_ffff_ffff,
0xffff_ffff_ffff_ffff,
0xffff_ffff_ffff_ffff,
0x0000_0000_0000_007f,
],
c2: FieldElement::from_hex(
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002",
),
map_a: FieldElement::from_u64(3).neg(),
map_b: FieldElement::from_hex(
"0000000000000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
),
z: FieldElement::from_u64(4).neg(),
};
}
impl MapToCurve for FieldElement {
type Output = ProjectivePoint;
fn map_to_curve(&self) -> Self::Output {
let (qx, qy) = self.osswu();
// TODO(tarcieri): assert that `qy` is correct? less circuitous conversion?
AffinePoint::decompress(&qx.to_bytes(), qy.is_odd())
.unwrap()
.into()
}
}
impl FromOkm for Scalar {
type Length = U98;
fn from_okm(data: &GenericArray<u8, Self::Length>) -> Self {
const F_2_392: Scalar = Scalar::from_hex(
"000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
);
let mut d0 = GenericArray::default();
d0[23..].copy_from_slice(&data[0..49]);
let d0 = Scalar::reduce(U576::from_be_byte_array(d0));
let mut d1 = GenericArray::default();
d1[23..].copy_from_slice(&data[49..]);
let d1 = Scalar::reduce(U576::from_be_byte_array(d1));
d0 * F_2_392 + d1
}
}
#[cfg(test)]
mod tests {
use crate::{
arithmetic::field::{FieldElement, MODULUS},
NistP521, Scalar,
};
use elliptic_curve::{
bigint::{ArrayEncoding, CheckedSub, NonZero, U576, U896},
consts::U98,
generic_array::GenericArray,
group::cofactor::CofactorGroup,
hash2curve::{self, ExpandMsgXmd, FromOkm, GroupDigest, MapToCurve, OsswuMap},
ops::Reduce,
sec1::{self, ToEncodedPoint},
Curve,
};
use hex_literal::hex;
use proptest::{num, prelude::ProptestConfig, proptest};
use sha2::Sha512;
#[test]
fn params() {
let params = <FieldElement as OsswuMap>::PARAMS;
let c1 = MODULUS.checked_sub(&U576::from_u8(3)).unwrap()
/ NonZero::new(U576::from_u8(4)).unwrap();
assert_eq!(
GenericArray::from_iter(params.c1.iter().rev().flat_map(|v| v.to_be_bytes())),
c1.to_be_byte_array()
);
let c2 = FieldElement::from_u64(4).sqrt().unwrap();
assert_eq!(params.c2, c2);
}
#[test]
fn hash_to_curve() {
struct TestVector {
msg: &'static [u8],
p_x: [u8; 66],
p_y: [u8; 66],
u_0: [u8; 66],
u_1: [u8; 66],
q0_x: [u8; 66],
q0_y: [u8; 66],
q1_x: [u8; 66],
q1_y: [u8; 66],
}
const DST: &[u8] = b"QUUX-V01-CS02-with-P521_XMD:SHA-512_SSWU_RO_";
const TEST_VECTORS: &[TestVector] = &[
TestVector {
msg: b"",
p_x: hex!("00fd767cebb2452030358d0e9cf907f525f50920c8f607889a6a35680727f64f4d66b161fafeb2654bea0d35086bec0a10b30b14adef3556ed9f7f1bc23cecc9c088"),
p_y: hex!("0169ba78d8d851e930680322596e39c78f4fe31b97e57629ef6460ddd68f8763fd7bd767a4e94a80d3d21a3c2ee98347e024fc73ee1c27166dc3fe5eeef782be411d"),
u_0: hex!("01e5f09974e5724f25286763f00ce76238c7a6e03dc396600350ee2c4135fb17dc555be99a4a4bae0fd303d4f66d984ed7b6a3ba386093752a855d26d559d69e7e9e"),
u_1: hex!("00ae593b42ca2ef93ac488e9e09a5fe5a2f6fb330d18913734ff602f2a761fcaaf5f596e790bcc572c9140ec03f6cccc38f767f1c1975a0b4d70b392d95a0c7278aa"),
q0_x: hex!("00b70ae99b6339fffac19cb9bfde2098b84f75e50ac1e80d6acb954e4534af5f0e9c4a5b8a9c10317b8e6421574bae2b133b4f2b8c6ce4b3063da1d91d34fa2b3a3c"),
q0_y: hex!("007f368d98a4ddbf381fb354de40e44b19e43bb11a1278759f4ea7b485e1b6db33e750507c071250e3e443c1aaed61f2c28541bb54b1b456843eda1eb15ec2a9b36e"),
q1_x: hex!("01143d0e9cddcdacd6a9aafe1bcf8d218c0afc45d4451239e821f5d2a56df92be942660b532b2aa59a9c635ae6b30e803c45a6ac871432452e685d661cd41cf67214"),
q1_y: hex!("00ff75515df265e996d702a5380defffab1a6d2bc232234c7bcffa433cd8aa791fbc8dcf667f08818bffa739ae25773b32073213cae9a0f2a917a0b1301a242dda0c"),
},
TestVector {
msg: b"abc",
p_x: hex!("002f89a1677b28054b50d15e1f81ed6669b5a2158211118ebdef8a6efc77f8ccaa528f698214e4340155abc1fa08f8f613ef14a043717503d57e267d57155cf784a4"),
p_y: hex!("010e0be5dc8e753da8ce51091908b72396d3deed14ae166f66d8ebf0a4e7059ead169ea4bead0232e9b700dd380b316e9361cfdba55a08c73545563a80966ecbb86d"),
u_0: hex!("003d00c37e95f19f358adeeaa47288ec39998039c3256e13c2a4c00a7cb61a34c8969472960150a27276f2390eb5e53e47ab193351c2d2d9f164a85c6a5696d94fe8"),
u_1: hex!("01f3cbd3df3893a45a2f1fecdac4d525eb16f345b03e2820d69bc580f5cbe9cb89196fdf720ef933c4c0361fcfe29940fd0db0a5da6bafb0bee8876b589c41365f15"),
q0_x: hex!("01b254e1c99c835836f0aceebba7d77750c48366ecb07fb658e4f5b76e229ae6ca5d271bb0006ffcc42324e15a6d3daae587f9049de2dbb0494378ffb60279406f56"),
q0_y: hex!("01845f4af72fc2b1a5a2fe966f6a97298614288b456cfc385a425b686048b25c952fbb5674057e1eb055d04568c0679a8e2dda3158dc16ac598dbb1d006f5ad915b0"),
q1_x: hex!("007f08e813c620e527c961b717ffc74aac7afccb9158cebc347d5715d5c2214f952c97e194f11d114d80d3481ed766ac0a3dba3eb73f6ff9ccb9304ad10bbd7b4a36"),
q1_y: hex!("0022468f92041f9970a7cc025d71d5b647f822784d29ca7b3bc3b0829d6bb8581e745f8d0cc9dc6279d0450e779ac2275c4c3608064ad6779108a7828ebd9954caeb"),
},
TestVector {
msg: b"abcdef0123456789",
p_x: hex!("006e200e276a4a81760099677814d7f8794a4a5f3658442de63c18d2244dcc957c645e94cb0754f95fcf103b2aeaf94411847c24187b89fb7462ad3679066337cbc4"),
p_y: hex!("001dd8dfa9775b60b1614f6f169089d8140d4b3e4012949b52f98db2deff3e1d97bf73a1fa4d437d1dcdf39b6360cc518d8ebcc0f899018206fded7617b654f6b168"),
u_0: hex!("00183ee1a9bbdc37181b09ec336bcaa34095f91ef14b66b1485c166720523dfb81d5c470d44afcb52a87b704dbc5c9bc9d0ef524dec29884a4795f55c1359945baf3"),
u_1: hex!("00504064fd137f06c81a7cf0f84aa7e92b6b3d56c2368f0a08f44776aa8930480da1582d01d7f52df31dca35ee0a7876500ece3d8fe0293cd285f790c9881c998d5e"),
q0_x: hex!("0021482e8622aac14da60e656043f79a6a110cbae5012268a62dd6a152c41594549f373910ebed170ade892dd5a19f5d687fae7095a461d583f8c4295f7aaf8cd7da"),
q0_y: hex!("0177e2d8c6356b7de06e0b5712d8387d529b848748e54a8bc0ef5f1475aa569f8f492fa85c3ad1c5edc51faf7911f11359bfa2a12d2ef0bd73df9cb5abd1b101c8b1"),
q1_x: hex!("00abeafb16fdbb5eb95095678d5a65c1f293291dfd20a3751dbe05d0a9bfe2d2eef19449fe59ec32cdd4a4adc3411177c0f2dffd0159438706159a1bbd0567d9b3d0"),
q1_y: hex!("007cc657f847db9db651d91c801741060d63dab4056d0a1d3524e2eb0e819954d8f677aa353bd056244a88f00017e00c3ce8beeedb4382d83d74418bd48930c6c182"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
p_x: hex!("01b264a630bd6555be537b000b99a06761a9325c53322b65bdc41bf196711f9708d58d34b3b90faf12640c27b91c70a507998e55940648caa8e71098bf2bc8d24664"),
p_y: hex!("01ea9f445bee198b3ee4c812dcf7b0f91e0881f0251aab272a12201fd89b1a95733fd2a699c162b639e9acdcc54fdc2f6536129b6beb0432be01aa8da02df5e59aaa"),
u_0: hex!("0159871e222689aad7694dc4c3480a49807b1eedd9c8cb4ae1b219d5ba51655ea5b38e2e4f56b36bf3e3da44a7b139849d28f598c816fe1bc7ed15893b22f63363c3"),
u_1: hex!("004ef0cffd475152f3858c0a8ccbdf7902d8261da92744e98df9b7fadb0a5502f29c5086e76e2cf498f47321434a40b1504911552ce44ad7356a04e08729ad9411f5"),
q0_x: hex!("0005eac7b0b81e38727efcab1e375f6779aea949c3e409b53a1d37aa2acbac87a7e6ad24aafbf3c52f82f7f0e21b872e88c55e17b7fa21ce08a94ea2121c42c2eb73"),
q0_y: hex!("00a173b6a53a7420dbd61d4a21a7c0a52de7a5c6ce05f31403bef747d16cc8604a039a73bdd6e114340e55dacd6bea8e217ffbadfb8c292afa3e1b2afc839a6ce7bb"),
q1_x: hex!("01881e3c193a69e4d88d8180a6879b74782a0bc7e529233e9f84bf7f17d2f319c36920ffba26f9e57a1e045cc7822c834c239593b6e142a694aa00c757b0db79e5e8"),
q1_y: hex!("01558b16d396d866e476e001f2dd0758927655450b84e12f154032c7c2a6db837942cd9f44b814f79b4d729996ced61eec61d85c675139cbffe3fbf071d2c21cfecb"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
p_x: hex!("00c12bc3e28db07b6b4d2a2b1167ab9e26fc2fa85c7b0498a17b0347edf52392856d7e28b8fa7a2dd004611159505835b687ecf1a764857e27e9745848c436ef3925"),
p_y: hex!("01cd287df9a50c22a9231beb452346720bb163344a41c5f5a24e8335b6ccc595fd436aea89737b1281aecb411eb835f0b939073fdd1dd4d5a2492e91ef4a3c55bcbd"),
u_0: hex!("0033d06d17bc3b9a3efc081a05d65805a14a3050a0dd4dfb4884618eb5c73980a59c5a246b18f58ad022dd3630faa22889fbb8ba1593466515e6ab4aeb7381c26334"),
u_1: hex!("0092290ab99c3fea1a5b8fb2ca49f859994a04faee3301cefab312d34227f6a2d0c3322cf76861c6a3683bdaa2dd2a6daa5d6906c663e065338b2344d20e313f1114"),
q0_x: hex!("00041f6eb92af8777260718e4c22328a7d74203350c6c8f5794d99d5789766698f459b83d5068276716f01429934e40af3d1111a22780b1e07e72238d2207e5386be"),
q0_y: hex!("001c712f0182813942b87cab8e72337db017126f52ed797dd234584ac9ae7e80dfe7abea11db02cf1855312eae1447dbaecc9d7e8c880a5e76a39f6258074e1bc2e0"),
q1_x: hex!("0125c0b69bcf55eab49280b14f707883405028e05c927cd7625d4e04115bd0e0e6323b12f5d43d0d6d2eff16dbcf244542f84ec058911260dc3bb6512ab5db285fbd"),
q1_y: hex!("008bddfb803b3f4c761458eb5f8a0aee3e1f7f68e9d7424405fa69172919899317fb6ac1d6903a432d967d14e0f80af63e7035aaae0c123e56862ce969456f99f102"),
},
];
for test_vector in TEST_VECTORS {
// in parts
let mut u = [FieldElement::default(), FieldElement::default()];
hash2curve::hash_to_field::<ExpandMsgXmd<Sha512>, FieldElement>(
&[test_vector.msg],
&[DST],
&mut u,
)
.unwrap();
/// Assert that the provided projective point matches the given test vector.
// TODO(tarcieri): use coordinate APIs. See zkcrypto/group#30
macro_rules! assert_point_eq {
($actual:expr, $expected_x:expr, $expected_y:expr) => {
let point = $actual.to_affine().to_encoded_point(false);
let (actual_x, actual_y) = match point.coordinates() {
sec1::Coordinates::Uncompressed { x, y } => (x, y),
_ => unreachable!(),
};
assert_eq!(&$expected_x, actual_x.as_slice());
assert_eq!(&$expected_y, actual_y.as_slice());
};
}
assert_eq!(u[0].to_bytes().as_slice(), test_vector.u_0);
assert_eq!(u[1].to_bytes().as_slice(), test_vector.u_1);
let q0 = u[0].map_to_curve();
assert_point_eq!(q0, test_vector.q0_x, test_vector.q0_y);
let q1 = u[1].map_to_curve();
assert_point_eq!(q1, test_vector.q1_x, test_vector.q1_y);
let p = q0.clear_cofactor() + q1.clear_cofactor();
assert_point_eq!(p, test_vector.p_x, test_vector.p_y);
// complete run
let pt = NistP521::hash_from_bytes::<ExpandMsgXmd<Sha512>>(&[test_vector.msg], &[DST])
.unwrap();
assert_point_eq!(pt, test_vector.p_x, test_vector.p_y);
}
}
/// Taken from <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-voprf#appendix-A.5>.
#[test]
fn hash_to_scalar_voprf() {
struct TestVector {
dst: &'static [u8],
key_info: &'static [u8],
seed: &'static [u8],
sk_sm: &'static [u8],
}
const TEST_VECTORS: &[TestVector] = &[
TestVector {
dst: b"DeriveKeyPairOPRFV1-\x00-P521-SHA512",
key_info: &hex!("74657374206b6579"),
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
sk_sm: &hex!("0153441b8faedb0340439036d6aed06d1217b34c42f17f8db4c5cc610a4a955d698a688831b16d0dc7713a1aa3611ec60703bffc7dc9c84e3ed673b3dbe1d5fccea6"),
},
TestVector {
dst: b"DeriveKeyPairOPRFV1-\x01-P521-SHA512",
key_info: b"test key",
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
sk_sm: &hex!("015c7fc1b4a0b1390925bae915bd9f3d72009d44d9241b962428aad5d13f22803311e7102632a39addc61ea440810222715c9d2f61f03ea424ec9ab1fe5e31cf9238"),
},
TestVector {
dst: b"DeriveKeyPairOPRFV1-\x02-P521-SHA512",
key_info: b"test key",
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
sk_sm: &hex!("014893130030ce69cf714f536498a02ff6b396888f9bb507985c32928c4427d6d39de10ef509aca4240e8569e3a88debc0d392e3361bcd934cb9bdd59e339dff7b27"),
},
];
'outer: for test_vector in TEST_VECTORS {
let key_info_len = u16::try_from(test_vector.key_info.len())
.unwrap()
.to_be_bytes();
for counter in 0_u8..=u8::MAX {
let scalar = NistP521::hash_to_scalar::<ExpandMsgXmd<Sha512>>(
&[
test_vector.seed,
&key_info_len,
test_vector.key_info,
&counter.to_be_bytes(),
],
&[test_vector.dst],
)
.unwrap();
if !bool::from(scalar.is_zero()) {
assert_eq!(scalar.to_bytes().as_slice(), test_vector.sk_sm);
continue 'outer;
}
}
panic!("deriving key failed");
}
}
#[test]
fn from_okm_fuzz() {
let mut wide_order = GenericArray::default();
wide_order[40..].copy_from_slice(NistP521::ORDER.to_be_byte_array().as_slice());
// TODO: This could be reduced to `U832` when `crypto-bigint` implements `ArrayEncoding`.
let wide_order = NonZero::new(U896::from_be_byte_array(wide_order)).unwrap();
let simple_from_okm = move |data: GenericArray<u8, U98>| -> Scalar {
let mut wide_data = GenericArray::default();
wide_data[14..].copy_from_slice(data.as_slice());
let wide_data = U896::from_be_byte_array(wide_data);
let scalar = wide_data % wide_order;
let reduced_scalar = U576::from_be_slice(&scalar.to_be_byte_array()[40..]);
Scalar::reduce(reduced_scalar)
};
proptest!(
ProptestConfig::with_cases(1000),
|(
b0 in num::u64::ANY,
b1 in num::u64::ANY,
b2 in num::u64::ANY,
b3 in num::u64::ANY,
b4 in num::u64::ANY,
b5 in num::u64::ANY,
b6 in num::u64::ANY,
b7 in num::u64::ANY,
b8 in num::u64::ANY,
b9 in num::u64::ANY,
b10 in num::u64::ANY,
b11 in num::u64::ANY,
b12 in num::u16::ANY,
)| {
let mut data = GenericArray::default();
data[..8].copy_from_slice(&b0.to_be_bytes());
data[8..16].copy_from_slice(&b1.to_be_bytes());
data[16..24].copy_from_slice(&b2.to_be_bytes());
data[24..32].copy_from_slice(&b3.to_be_bytes());
data[32..40].copy_from_slice(&b4.to_be_bytes());
data[40..48].copy_from_slice(&b5.to_be_bytes());
data[48..56].copy_from_slice(&b6.to_be_bytes());
data[56..64].copy_from_slice(&b7.to_be_bytes());
data[64..72].copy_from_slice(&b8.to_be_bytes());
data[72..80].copy_from_slice(&b9.to_be_bytes());
data[80..88].copy_from_slice(&b10.to_be_bytes());
data[88..96].copy_from_slice(&b11.to_be_bytes());
data[96..].copy_from_slice(&b12.to_be_bytes());
let from_okm = Scalar::from_okm(&data);
let simple_from_okm = simple_from_okm(data);
assert_eq!(from_okm, simple_from_okm);
}
);
}
}

699
vendor/p521/src/arithmetic/scalar.rs vendored Normal file
View File

@@ -0,0 +1,699 @@
//! secp521r1 scalar field elements.
//!
//! Arithmetic implementations have been synthesized using fiat-crypto.
//!
//! # License
//!
//! Copyright (c) 2015-2020 the fiat-crypto authors
//!
//! fiat-crypto is distributed under the terms of the MIT License, the
//! Apache License (Version 2.0), and the BSD 1-Clause License;
//! users may pick which license to apply.
// TODO(tarcieri): 32-bit backend?
#[path = "scalar/p521_scalar_64.rs"]
mod scalar_impl;
use self::scalar_impl::*;
use crate::{FieldBytes, NistP521, SecretKey, U576};
use core::{
iter::{Product, Sum},
ops::{AddAssign, MulAssign, Neg, Shr, ShrAssign, SubAssign},
};
use elliptic_curve::{
bigint::{self, Integer},
ff::{self, Field, PrimeField},
generic_array::GenericArray,
ops::{Invert, Reduce},
rand_core::RngCore,
scalar::{FromUintUnchecked, IsHigh},
subtle::{
Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
CtOption,
},
zeroize::DefaultIsZeroes,
Curve as _, Error, FieldBytesEncoding, Result, ScalarPrimitive,
};
use primeorder::{impl_bernstein_yang_invert, impl_field_op};
#[cfg(feature = "bits")]
use {crate::ScalarBits, elliptic_curve::group::ff::PrimeFieldBits};
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
#[cfg(doc)]
use core::ops::{Add, Mul, Sub};
#[cfg(target_pointer_width = "32")]
use super::util::{u32x18_to_u64x9, u64x9_to_u32x18};
/// Scalars are elements in the finite field modulo `n`.
///
/// # Trait impls
///
/// Much of the important functionality of scalars is provided by traits from
/// the [`ff`](https://docs.rs/ff/) crate, which is re-exported as
/// `p521::elliptic_curve::ff`:
///
/// - [`Field`](https://docs.rs/ff/latest/ff/trait.Field.html) -
/// represents elements of finite fields and provides:
/// - [`Field::random`](https://docs.rs/ff/latest/ff/trait.Field.html#tymethod.random) -
/// generate a random scalar
/// - `double`, `square`, and `invert` operations
/// - Bounds for [`Add`], [`Sub`], [`Mul`], and [`Neg`] (as well as `*Assign` equivalents)
/// - Bounds for [`ConditionallySelectable`] from the `subtle` crate
/// - [`PrimeField`](https://docs.rs/ff/latest/ff/trait.PrimeField.html) -
/// represents elements of prime fields and provides:
/// - `from_repr`/`to_repr` for converting field elements from/to big integers.
/// - `multiplicative_generator` and `root_of_unity` constants.
/// - [`PrimeFieldBits`](https://docs.rs/ff/latest/ff/trait.PrimeFieldBits.html) -
/// operations over field elements represented as bits (requires `bits` feature)
///
/// Please see the documentation for the relevant traits for more information.
#[derive(Clone, Copy, Debug, PartialOrd, Ord)]
pub struct Scalar(fiat_p521_scalar_montgomery_domain_field_element);
impl Scalar {
/// Zero element.
pub const ZERO: Self = Self::from_u64(0);
/// Multiplicative identity.
pub const ONE: Self = Self::from_u64(1);
/// Number of bytes in the serialized representation.
const BYTES: usize = 66;
/// Create a [`Scalar`] from a canonical big-endian representation.
pub fn from_bytes(repr: &FieldBytes) -> CtOption<Self> {
Self::from_uint(FieldBytesEncoding::<NistP521>::decode_field_bytes(repr))
}
/// Decode [`Scalar`] from a big endian byte slice.
pub fn from_slice(slice: &[u8]) -> Result<Self> {
if slice.len() != Self::BYTES {
return Err(Error);
}
Option::from(Self::from_bytes(GenericArray::from_slice(slice))).ok_or(Error)
}
/// Decode [`Scalar`] from [`U576`] converting it into Montgomery form:
///
/// ```text
/// w * R^2 * R^-1 mod p = wR mod p
/// ```
pub fn from_uint(uint: U576) -> CtOption<Self> {
let is_some = uint.ct_lt(&NistP521::ORDER);
CtOption::new(Self::from_uint_unchecked(uint), is_some)
}
/// Parse a [`Scalar`] from big endian hex-encoded bytes.
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// This method is primarily intended for defining internal constants.
#[allow(dead_code)]
pub(crate) const fn from_hex(hex: &str) -> Self {
Self::from_uint_unchecked(U576::from_be_hex(hex))
}
/// Convert a `u64` into a [`Scalar`].
pub const fn from_u64(w: u64) -> Self {
Self::from_uint_unchecked(U576::from_u64(w))
}
/// Decode [`Scalar`] from [`U576`] converting it into Montgomery form.
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// Used incorrectly this can lead to invalid results!
#[cfg(target_pointer_width = "32")]
pub(crate) const fn from_uint_unchecked(w: U576) -> Self {
Self(fiat_p521_scalar_to_montgomery(&u32x18_to_u64x9(
w.as_words(),
)))
}
/// Decode [`Scalar`] from [`U576`] converting it into Montgomery form.
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// Used incorrectly this can lead to invalid results!
#[cfg(target_pointer_width = "64")]
pub(crate) const fn from_uint_unchecked(w: U576) -> Self {
Self(fiat_p521_scalar_to_montgomery(w.as_words()))
}
/// Returns the big-endian encoding of this [`Scalar`].
pub fn to_bytes(self) -> FieldBytes {
FieldBytesEncoding::<NistP521>::encode_field_bytes(&self.to_canonical())
}
/// Translate [`Scalar`] out of the Montgomery domain, returning a [`U576`]
/// in canonical form.
#[inline]
#[cfg(target_pointer_width = "32")]
pub const fn to_canonical(self) -> U576 {
U576::from_words(u64x9_to_u32x18(&fiat_p521_scalar_from_montgomery(&self.0)))
}
/// Translate [`Scalar`] out of the Montgomery domain, returning a [`U576`]
/// in canonical form.
#[inline]
#[cfg(target_pointer_width = "64")]
pub const fn to_canonical(self) -> U576 {
U576::from_words(fiat_p521_scalar_from_montgomery(&self.0))
}
/// Determine if this [`Scalar`] is odd in the SEC1 sense: `self mod 2 == 1`.
///
/// # Returns
///
/// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_odd(&self) -> Choice {
self.to_canonical().is_odd()
}
/// Determine if this [`Scalar`] is even in the SEC1 sense: `self mod 2 == 0`.
///
/// # Returns
///
/// If even, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_even(&self) -> Choice {
!self.is_odd()
}
/// Determine if this [`Scalar`] is zero.
///
/// # Returns
///
/// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_zero(&self) -> Choice {
self.ct_eq(&Self::ZERO)
}
/// Add elements.
pub const fn add(&self, rhs: &Self) -> Self {
Self(fiat_p521_scalar_add(&self.0, &rhs.0))
}
/// Double element (add it to itself).
#[must_use]
pub const fn double(&self) -> Self {
self.add(self)
}
/// Subtract elements.
pub const fn sub(&self, rhs: &Self) -> Self {
Self(fiat_p521_scalar_sub(&self.0, &rhs.0))
}
/// Negate element.
pub const fn neg(&self) -> Self {
Self(fiat_p521_scalar_opp(&self.0))
}
/// Multiply elements.
pub const fn multiply(&self, rhs: &Self) -> Self {
Self(fiat_p521_scalar_mul(&self.0, &rhs.0))
}
/// Compute [`Scalar`] inversion: `1 / self`.
pub fn invert(&self) -> CtOption<Self> {
CtOption::new(self.invert_unchecked(), !self.is_zero())
}
/// Compute [`Scalar`] inversion: `1 / self`.
///
/// Does not check that self is non-zero.
const fn invert_unchecked(&self) -> Self {
let words = impl_bernstein_yang_invert!(
&self.0,
Self::ONE.0,
521,
9,
u64,
fiat_p521_scalar_from_montgomery,
fiat_p521_scalar_mul,
fiat_p521_scalar_opp,
fiat_p521_scalar_divstep_precomp,
fiat_p521_scalar_divstep,
fiat_p521_scalar_msat,
fiat_p521_scalar_selectznz,
);
Self(words)
}
/// Compute modular square.
#[must_use]
pub const fn square(&self) -> Self {
Self(fiat_p521_scalar_square(&self.0))
}
/// Compute modular square root.
pub fn sqrt(&self) -> CtOption<Self> {
todo!("`sqrt` not yet implemented")
}
/// Returns `self^exp`, where `exp` is a little-endian integer exponent.
///
/// **This operation is variable time with respect to the exponent.**
///
/// If the exponent is fixed, this operation is effectively constant time.
pub const fn pow_vartime(&self, exp: &[u64]) -> Self {
let mut res = Self::ONE;
let mut i = exp.len();
while i > 0 {
i -= 1;
let mut j = 64;
while j > 0 {
j -= 1;
res = res.square();
if ((exp[i] >> j) & 1) == 1 {
res = res.multiply(self);
}
}
}
res
}
/// Right shifts the scalar.
///
/// Note: not constant-time with respect to the `shift` parameter.
#[cfg(target_pointer_width = "32")]
pub const fn shr_vartime(&self, shift: usize) -> Scalar {
Self(u32x18_to_u64x9(
&U576::from_words(u64x9_to_u32x18(&self.0))
.shr_vartime(shift)
.to_words(),
))
}
/// Right shifts the scalar.
///
/// Note: not constant-time with respect to the `shift` parameter.
#[cfg(target_pointer_width = "64")]
pub const fn shr_vartime(&self, shift: usize) -> Scalar {
Self(U576::from_words(self.0).shr_vartime(shift).to_words())
}
}
impl AsRef<fiat_p521_scalar_montgomery_domain_field_element> for Scalar {
fn as_ref(&self) -> &fiat_p521_scalar_montgomery_domain_field_element {
&self.0
}
}
impl Default for Scalar {
fn default() -> Self {
Self::ZERO
}
}
impl Eq for Scalar {}
impl PartialEq for Scalar {
fn eq(&self, rhs: &Self) -> bool {
self.0.ct_eq(&(rhs.0)).into()
}
}
impl From<u32> for Scalar {
fn from(n: u32) -> Scalar {
Self::from_uint_unchecked(U576::from(n))
}
}
impl From<u64> for Scalar {
fn from(n: u64) -> Scalar {
Self::from_uint_unchecked(U576::from(n))
}
}
impl From<u128> for Scalar {
fn from(n: u128) -> Scalar {
Self::from_uint_unchecked(U576::from(n))
}
}
impl ConditionallySelectable for Scalar {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
let mut ret = Self::ZERO;
for i in 0..ret.0.len() {
ret.0[i] = u64::conditional_select(&a.0[i], &b.0[i], choice);
}
ret
}
}
impl ConstantTimeEq for Scalar {
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&other.0)
}
}
impl DefaultIsZeroes for Scalar {}
impl Field for Scalar {
const ZERO: Self = Self::ZERO;
const ONE: Self = Self::ONE;
fn random(mut rng: impl RngCore) -> Self {
// NOTE: can't use ScalarPrimitive::random due to CryptoRng bound
let mut bytes = <FieldBytes>::default();
loop {
rng.fill_bytes(&mut bytes);
if let Some(fe) = Self::from_bytes(&bytes).into() {
return fe;
}
}
}
fn is_zero(&self) -> Choice {
Self::ZERO.ct_eq(self)
}
#[must_use]
fn square(&self) -> Self {
self.square()
}
#[must_use]
fn double(&self) -> Self {
self.double()
}
fn invert(&self) -> CtOption<Self> {
self.invert()
}
fn sqrt(&self) -> CtOption<Self> {
self.sqrt()
}
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
ff::helpers::sqrt_ratio_generic(num, div)
}
}
impl_field_op!(Scalar, Add, add, fiat_p521_scalar_add);
impl_field_op!(Scalar, Sub, sub, fiat_p521_scalar_sub);
impl_field_op!(Scalar, Mul, mul, fiat_p521_scalar_mul);
impl AddAssign<Scalar> for Scalar {
#[inline]
fn add_assign(&mut self, other: Scalar) {
*self = *self + other;
}
}
impl AddAssign<&Scalar> for Scalar {
#[inline]
fn add_assign(&mut self, other: &Scalar) {
*self = *self + other;
}
}
impl SubAssign<Scalar> for Scalar {
#[inline]
fn sub_assign(&mut self, other: Scalar) {
*self = *self - other;
}
}
impl SubAssign<&Scalar> for Scalar {
#[inline]
fn sub_assign(&mut self, other: &Scalar) {
*self = *self - other;
}
}
impl MulAssign<&Scalar> for Scalar {
#[inline]
fn mul_assign(&mut self, other: &Scalar) {
*self = *self * other;
}
}
impl MulAssign for Scalar {
#[inline]
fn mul_assign(&mut self, other: Scalar) {
*self = *self * other;
}
}
impl Neg for Scalar {
type Output = Scalar;
#[inline]
fn neg(self) -> Scalar {
Self::neg(&self)
}
}
impl Sum for Scalar {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO)
}
}
impl<'a> Sum<&'a Scalar> for Scalar {
fn sum<I: Iterator<Item = &'a Scalar>>(iter: I) -> Self {
iter.copied().sum()
}
}
impl Product for Scalar {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE)
}
}
impl<'a> Product<&'a Scalar> for Scalar {
fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
iter.copied().product()
}
}
impl AsRef<Scalar> for Scalar {
fn as_ref(&self) -> &Scalar {
self
}
}
impl FromUintUnchecked for Scalar {
type Uint = U576;
fn from_uint_unchecked(uint: Self::Uint) -> Self {
Self::from_uint_unchecked(uint)
}
}
impl Invert for Scalar {
type Output = CtOption<Self>;
fn invert(&self) -> CtOption<Self> {
self.invert()
}
}
impl IsHigh for Scalar {
fn is_high(&self) -> Choice {
const MODULUS_SHR1: U576 = NistP521::ORDER.shr_vartime(1);
self.to_canonical().ct_gt(&MODULUS_SHR1)
}
}
impl Shr<usize> for Scalar {
type Output = Self;
fn shr(self, rhs: usize) -> Self::Output {
self.shr_vartime(rhs)
}
}
impl Shr<usize> for &Scalar {
type Output = Scalar;
fn shr(self, rhs: usize) -> Self::Output {
self.shr_vartime(rhs)
}
}
impl ShrAssign<usize> for Scalar {
fn shr_assign(&mut self, rhs: usize) {
*self = *self >> rhs;
}
}
impl PrimeField for Scalar {
type Repr = FieldBytes;
const MODULUS: &'static str = "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409";
const CAPACITY: u32 = 520;
const NUM_BITS: u32 = 521;
const TWO_INV: Self = Self::from_u64(2).invert_unchecked();
const MULTIPLICATIVE_GENERATOR: Self = Self::from_u64(3);
const S: u32 = 3;
const ROOT_OF_UNITY: Self = Self::from_hex("000000000000009a0a650d44b28c17f3d708ad2fa8c4fbc7e6000d7c12dafa92fcc5673a3055276d535f79ff391dcdbcd998b7836647d3a72472b3da861ac810a7f9c7b7b63e2205");
const ROOT_OF_UNITY_INV: Self = Self::ROOT_OF_UNITY.invert_unchecked();
const DELTA: Self = Self::from_u64(6561);
#[inline]
fn from_repr(bytes: FieldBytes) -> CtOption<Self> {
Self::from_bytes(&bytes)
}
#[inline]
fn to_repr(&self) -> FieldBytes {
self.to_bytes()
}
#[inline]
fn is_odd(&self) -> Choice {
self.is_odd()
}
}
#[cfg(feature = "bits")]
impl PrimeFieldBits for Scalar {
type ReprBits = fiat_p521_scalar_montgomery_domain_field_element;
fn to_le_bits(&self) -> ScalarBits {
self.to_canonical().to_words().into()
}
fn char_le_bits() -> ScalarBits {
NistP521::ORDER.to_words().into()
}
}
impl Reduce<U576> for Scalar {
type Bytes = FieldBytes;
fn reduce(w: U576) -> Self {
let (r, underflow) = w.sbb(&NistP521::ORDER, bigint::Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (bigint::Limb::BITS - 1)) as u8);
Self::from_uint_unchecked(U576::conditional_select(&w, &r, !underflow))
}
#[inline]
fn reduce_bytes(bytes: &FieldBytes) -> Self {
let w = <U576 as FieldBytesEncoding<NistP521>>::decode_field_bytes(bytes);
Self::reduce(w)
}
}
impl From<ScalarPrimitive<NistP521>> for Scalar {
fn from(w: ScalarPrimitive<NistP521>) -> Self {
Scalar::from(&w)
}
}
impl From<&ScalarPrimitive<NistP521>> for Scalar {
fn from(w: &ScalarPrimitive<NistP521>) -> Scalar {
Scalar::from_uint_unchecked(*w.as_uint())
}
}
impl From<Scalar> for ScalarPrimitive<NistP521> {
fn from(scalar: Scalar) -> ScalarPrimitive<NistP521> {
ScalarPrimitive::from(&scalar)
}
}
impl From<&Scalar> for ScalarPrimitive<NistP521> {
fn from(scalar: &Scalar) -> ScalarPrimitive<NistP521> {
ScalarPrimitive::new(scalar.into()).unwrap()
}
}
impl From<Scalar> for FieldBytes {
fn from(scalar: Scalar) -> Self {
scalar.to_repr()
}
}
impl From<&Scalar> for FieldBytes {
fn from(scalar: &Scalar) -> Self {
scalar.to_repr()
}
}
impl From<Scalar> for U576 {
fn from(scalar: Scalar) -> U576 {
U576::from(&scalar)
}
}
impl From<&Scalar> for U576 {
fn from(scalar: &Scalar) -> U576 {
scalar.to_canonical()
}
}
impl From<&SecretKey> for Scalar {
fn from(secret_key: &SecretKey) -> Scalar {
*secret_key.to_nonzero_scalar()
}
}
impl TryFrom<U576> for Scalar {
type Error = Error;
fn try_from(w: U576) -> Result<Self> {
Option::from(Self::from_uint(w)).ok_or(Error)
}
}
#[cfg(feature = "serde")]
impl Serialize for Scalar {
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
ScalarPrimitive::from(self).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Scalar {
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
Ok(ScalarPrimitive::deserialize(deserializer)?.into())
}
}
#[cfg(test)]
mod tests {
use super::Scalar;
use elliptic_curve::PrimeField;
use primeorder::{impl_field_identity_tests, impl_field_invert_tests, impl_primefield_tests};
/// t = (modulus - 1) >> S
const T: [u64; 9] = [
0xd76df6e3d2270c81,
0x0776b937113388f5,
0x6ff980291ee134ba,
0x4a30d0f077e5f2cd,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0x000000000000003f,
];
impl_field_identity_tests!(Scalar);
impl_field_invert_tests!(Scalar);
impl_primefield_tests!(Scalar, T);
}

File diff suppressed because it is too large Load Diff

64
vendor/p521/src/arithmetic/util.rs vendored Normal file
View File

@@ -0,0 +1,64 @@
//! Utility functions.
use elliptic_curve::bigint::U576;
/// Convert an 18-element array of `u32` into a 9-element array of `u16`,
/// assuming integer arrays are in little-endian order.
#[cfg(target_pointer_width = "32")]
pub(crate) const fn u32x18_to_u64x9(w: &[u32; 18]) -> [u64; 9] {
let mut ret = [0u64; 9];
let mut i = 0;
while i < 9 {
ret[i] = (w[i * 2] as u64) | ((w[(i * 2) + 1] as u64) << 32);
i += 1;
}
ret
}
/// Convert a 9-element array of `u64` into an 18-element array of `u32`,
/// assuming integers are in little-endian order.
#[cfg(target_pointer_width = "32")]
pub(crate) const fn u64x9_to_u32x18(w: &[u64; 9]) -> [u32; 18] {
let mut ret = [0u32; 18];
let mut i = 0;
while i < 9 {
ret[i * 2] = (w[i] & 0xFFFFFFFF) as u32;
ret[(i * 2) + 1] = (w[i] >> 32) as u32;
i += 1;
}
ret
}
/// Converts the saturated representation [`U576`] into a 528bit array. Each
/// word is copied in little-endian.
pub const fn u576_to_le_bytes(w: U576) -> [u8; 66] {
#[cfg(target_pointer_width = "32")]
let words = u32x18_to_u64x9(w.as_words());
#[cfg(target_pointer_width = "64")]
let words = w.as_words();
let mut result: [u8; 66] = [0u8; 66];
let mut i = 0;
while i < words.len() - 1 {
let word = words[i].to_le_bytes();
let start = i * 8;
result[start] = word[0];
result[start + 1] = word[1];
result[start + 2] = word[2];
result[start + 3] = word[3];
result[start + 4] = word[4];
result[start + 5] = word[5];
result[start + 6] = word[6];
result[start + 7] = word[7];
i += 1;
}
let last_word = words[8].to_le_bytes();
result[i * 8] = last_word[0];
result[(i * 8) + 1] = last_word[1];
result
}

47
vendor/p521/src/ecdh.rs vendored Normal file
View File

@@ -0,0 +1,47 @@
//! Elliptic Curve Diffie-Hellman (Ephemeral) Support.
//!
//! This module contains a high-level interface for performing ephemeral
//! Diffie-Hellman key exchanges using the secp521r1 elliptic curve.
//!
//! # Usage
//!
//! This usage example is from the perspective of two participants in the
//! exchange, nicknamed "Alice" and "Bob".
//!
//! ```
//! use p521::{EncodedPoint, PublicKey, ecdh::EphemeralSecret};
//! use rand_core::OsRng; // requires 'getrandom' feature
//!
//! // Alice
//! let alice_secret = EphemeralSecret::random(&mut OsRng);
//! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key());
//!
//! // Bob
//! let bob_secret = EphemeralSecret::random(&mut OsRng);
//! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key());
//!
//! // Alice decodes Bob's serialized public key and computes a shared secret from it
//! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref())
//! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this!
//!
//! let alice_shared = alice_secret.diffie_hellman(&bob_public);
//!
//! // Bob decodes Alice's serialized public key and computes the same shared secret
//! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref())
//! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this!
//!
//! let bob_shared = bob_secret.diffie_hellman(&alice_public);
//!
//! // Both participants arrive on the same shared secret
//! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes());
//! ```
pub use elliptic_curve::ecdh::diffie_hellman;
use crate::NistP521;
/// NIST P-521 Ephemeral Diffie-Hellman Secret.
pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret<NistP521>;
/// Shared secret value computed via ECDH key agreement.
pub type SharedSecret = elliptic_curve::ecdh::SharedSecret<NistP521>;

329
vendor/p521/src/ecdsa.rs vendored Normal file
View File

@@ -0,0 +1,329 @@
//! Elliptic Curve Digital Signature Algorithm (ECDSA)
//!
//! This module contains support for computing and verifying ECDSA signatures.
//! To use it, you will need to enable one of the two following Cargo features:
//!
//! - `ecdsa-core`: provides only the [`Signature`] type (which represents an
//! ECDSA/P-521 signature). Does not require the `arithmetic` feature. This is
//! useful for 3rd-party crates which wish to use the `Signature` type for
//! interoperability purposes (particularly in conjunction with the
//! [`signature::Signer`] trait. Example use cases for this include other
//! software implementations of ECDSA/P-521 and wrappers for cloud KMS
//! services or hardware devices (HSM or crypto hardware wallet).
//! - `ecdsa`: provides `ecdsa-core` features plus the [`SigningKey`] and
//! [`VerifyingKey`] types which natively implement ECDSA/P-521 signing and
//! verification.
//!
//! ## Signing/Verification Example
//!
//! This example requires the `ecdsa` Cargo feature is enabled:
//!
//! ```
//! # #[cfg(feature = "ecdsa")]
//! # {
//! use p521::ecdsa::{signature::Signer, Signature, SigningKey};
//! use rand_core::OsRng; // requires 'getrandom' feature
//!
//! // Signing
//! let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()`
//! let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
//! let signature: Signature = signing_key.sign(message);
//!
//! // Verification
//! use p521::ecdsa::{signature::Verifier, VerifyingKey};
//!
//! let verifying_key = VerifyingKey::from(&signing_key); // Serialize with `::to_encoded_point()`
//! assert!(verifying_key.verify(message, &signature).is_ok());
//! # }
//! ```
// TODO(tarcieri): use RFC6979 + upstream types from the `ecdsa` crate
pub use ecdsa_core::signature::{self, Error, Result};
#[cfg(feature = "ecdsa")]
use {
crate::{AffinePoint, EncodedPoint, FieldBytes, NonZeroScalar, Scalar},
ecdsa_core::{
hazmat::{bits2field, sign_prehashed, SignPrimitive, VerifyPrimitive},
signature::{
hazmat::{PrehashVerifier, RandomizedPrehashSigner},
rand_core::CryptoRngCore,
RandomizedSigner, Verifier,
},
},
elliptic_curve::Field,
sha2::{Digest, Sha512},
};
#[cfg(all(feature = "ecdsa", feature = "getrandom"))]
use {
ecdsa_core::signature::{hazmat::PrehashSigner, Signer},
rand_core::OsRng,
};
use super::NistP521;
/// ECDSA/P-521 signature (fixed-size)
pub type Signature = ecdsa_core::Signature<NistP521>;
/// ECDSA/P-521 signature (ASN.1 DER encoded)
pub type DerSignature = ecdsa_core::der::Signature<NistP521>;
#[cfg(feature = "ecdsa")]
impl SignPrimitive<NistP521> for Scalar {}
#[cfg(feature = "ecdsa")]
impl VerifyPrimitive<NistP521> for AffinePoint {}
/// ECDSA/P-521 signing key
#[cfg(feature = "ecdsa")]
#[derive(Clone)]
pub struct SigningKey(ecdsa_core::SigningKey<NistP521>);
#[cfg(feature = "ecdsa")]
impl SigningKey {
/// Generate a cryptographically random [`SigningKey`].
pub fn random(rng: &mut impl CryptoRngCore) -> Self {
ecdsa_core::SigningKey::<NistP521>::random(rng).into()
}
/// Initialize signing key from a raw scalar serialized as a byte array.
pub fn from_bytes(bytes: &FieldBytes) -> Result<Self> {
ecdsa_core::SigningKey::<NistP521>::from_bytes(bytes).map(Into::into)
}
/// Initialize signing key from a raw scalar serialized as a byte slice.
pub fn from_slice(bytes: &[u8]) -> Result<Self> {
ecdsa_core::SigningKey::<NistP521>::from_slice(bytes).map(Into::into)
}
/// Serialize this [`SigningKey`] as bytes
pub fn to_bytes(&self) -> FieldBytes {
self.0.to_bytes()
}
/// Borrow the secret [`NonZeroScalar`] value for this key.
///
/// # ⚠️ Warning
///
/// This value is key material.
///
/// Please treat it with the care it deserves!
pub fn as_nonzero_scalar(&self) -> &NonZeroScalar {
self.0.as_nonzero_scalar()
}
/// Get the [`VerifyingKey`] which corresponds to this [`SigningKey`].
#[cfg(feature = "verifying")]
pub fn verifying_key(&self) -> VerifyingKey {
VerifyingKey::from(self)
}
}
#[cfg(feature = "ecdsa")]
impl From<ecdsa_core::SigningKey<NistP521>> for SigningKey {
fn from(inner: ecdsa_core::SigningKey<NistP521>) -> SigningKey {
SigningKey(inner)
}
}
#[cfg(all(feature = "ecdsa", feature = "getrandom"))]
impl PrehashSigner<Signature> for SigningKey {
fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature> {
self.sign_prehash_with_rng(&mut OsRng, prehash)
}
}
#[cfg(feature = "ecdsa")]
impl RandomizedPrehashSigner<Signature> for SigningKey {
fn sign_prehash_with_rng(
&self,
rng: &mut impl CryptoRngCore,
prehash: &[u8],
) -> Result<Signature> {
let z = bits2field::<NistP521>(prehash)?;
let k = Scalar::random(rng);
sign_prehashed(self.0.as_nonzero_scalar().as_ref(), k, &z).map(|sig| sig.0)
}
}
#[cfg(feature = "ecdsa")]
impl RandomizedSigner<Signature> for SigningKey {
fn try_sign_with_rng(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> Result<Signature> {
self.sign_prehash_with_rng(rng, &Sha512::digest(msg))
}
}
#[cfg(all(feature = "ecdsa", feature = "getrandom"))]
impl Signer<Signature> for SigningKey {
fn try_sign(&self, msg: &[u8]) -> Result<Signature> {
self.try_sign_with_rng(&mut OsRng, msg)
}
}
/// ECDSA/P-521 verification key (i.e. public key)
#[cfg(feature = "ecdsa")]
#[derive(Clone)]
pub struct VerifyingKey(ecdsa_core::VerifyingKey<NistP521>);
#[cfg(feature = "ecdsa")]
impl VerifyingKey {
/// Initialize [`VerifyingKey`] from a SEC1-encoded public key.
pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
ecdsa_core::VerifyingKey::<NistP521>::from_sec1_bytes(bytes).map(Into::into)
}
/// Initialize [`VerifyingKey`] from an affine point.
///
/// Returns an [`Error`] if the given affine point is the additive identity
/// (a.k.a. point at infinity).
pub fn from_affine(affine: AffinePoint) -> Result<Self> {
ecdsa_core::VerifyingKey::<NistP521>::from_affine(affine).map(Into::into)
}
/// Initialize [`VerifyingKey`] from an [`EncodedPoint`].
pub fn from_encoded_point(public_key: &EncodedPoint) -> Result<Self> {
ecdsa_core::VerifyingKey::<NistP521>::from_encoded_point(public_key).map(Into::into)
}
/// Serialize this [`VerifyingKey`] as a SEC1 [`EncodedPoint`], optionally
/// applying point compression.
pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
self.0.to_encoded_point(compress)
}
/// Borrow the inner [`AffinePoint`] for this public key.
pub fn as_affine(&self) -> &AffinePoint {
self.0.as_affine()
}
}
#[cfg(feature = "ecdsa")]
impl From<&SigningKey> for VerifyingKey {
fn from(signing_key: &SigningKey) -> VerifyingKey {
Self::from(*signing_key.0.verifying_key())
}
}
#[cfg(feature = "ecdsa")]
impl From<ecdsa_core::VerifyingKey<NistP521>> for VerifyingKey {
fn from(inner: ecdsa_core::VerifyingKey<NistP521>) -> VerifyingKey {
VerifyingKey(inner)
}
}
#[cfg(feature = "ecdsa")]
impl PrehashVerifier<Signature> for VerifyingKey {
fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> Result<()> {
self.0.verify_prehash(prehash, signature)
}
}
#[cfg(feature = "ecdsa")]
impl Verifier<Signature> for VerifyingKey {
fn verify(&self, msg: &[u8], signature: &Signature) -> Result<()> {
self.verify_prehash(&Sha512::digest(msg), signature)
}
}
#[cfg(all(test, feature = "ecdsa", feature = "getrandom"))]
mod tests {
// TODO(tarcieri): RFC6979 support + test vectors
mod sign {
use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP521};
ecdsa_core::new_signing_test!(NistP521, ECDSA_TEST_VECTORS);
}
mod verify {
use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP521};
ecdsa_core::new_verification_test!(NistP521, ECDSA_TEST_VECTORS);
}
mod wycheproof {
use crate::{
ecdsa::{Signature, Verifier, VerifyingKey},
EncodedPoint, NistP521,
};
// TODO: use ecdsa_core::new_wycheproof_test!(wycheproof, "wycheproof", NistP521);
#[test]
fn wycheproof() {
use blobby::Blob5Iterator;
use elliptic_curve::generic_array::typenum::Unsigned;
// Build a field element but allow for too-short input (left pad with zeros)
// or too-long input (check excess leftmost bytes are zeros).
fn element_from_padded_slice<C: elliptic_curve::Curve>(
data: &[u8],
) -> elliptic_curve::FieldBytes<C> {
let point_len = C::FieldBytesSize::USIZE;
if data.len() >= point_len {
let offset = data.len() - point_len;
for v in data.iter().take(offset) {
assert_eq!(*v, 0, "EcdsaVerifier: point too large");
}
elliptic_curve::FieldBytes::<C>::clone_from_slice(&data[offset..])
} else {
// Provided slice is too short and needs to be padded with zeros
// on the left. Build a combined exact iterator to do this.
let iter = core::iter::repeat(0)
.take(point_len - data.len())
.chain(data.iter().cloned());
elliptic_curve::FieldBytes::<C>::from_exact_iter(iter).unwrap()
}
}
fn run_test(
wx: &[u8],
wy: &[u8],
msg: &[u8],
sig: &[u8],
pass: bool,
) -> Option<&'static str> {
let x = element_from_padded_slice::<NistP521>(wx);
let y = element_from_padded_slice::<NistP521>(wy);
let q_encoded =
EncodedPoint::from_affine_coordinates(&x, &y, /* compress= */ false);
let verifying_key = VerifyingKey::from_encoded_point(&q_encoded).unwrap();
let sig = match Signature::from_der(sig) {
Ok(s) => s,
Err(_) if !pass => return None,
Err(_) => return Some("failed to parse signature ASN.1"),
};
match verifying_key.verify(msg, &sig) {
Ok(_) if pass => None,
Ok(_) => Some("signature verify unexpectedly succeeded"),
Err(_) if !pass => None,
Err(_) => Some("signature verify failed"),
}
}
let data = include_bytes!(concat!("test_vectors/data/wycheproof.blb"));
for (i, row) in Blob5Iterator::new(data).unwrap().enumerate() {
let [wx, wy, msg, sig, status] = row.unwrap();
let pass = match status[0] {
0 => false,
1 => true,
_ => panic!("invalid value for pass flag"),
};
if let Some(desc) = run_test(wx, wy, msg, sig, pass) {
panic!(
"\n\
Failed test №{}: {}\n\
wx:\t{:?}\n\
wy:\t{:?}\n\
msg:\t{:?}\n\
sig:\t{:?}\n\
pass:\t{}\n",
i, desc, wx, wy, msg, sig, pass,
);
}
}
}
}
}

119
vendor/p521/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,119 @@
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
#![forbid(unsafe_code)]
#![warn(
clippy::mod_module_files,
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
//! ## `serde` support
//!
//! When the `serde` feature of this crate is enabled, `Serialize` and
//! `Deserialize` are impl'd for the following types:
//!
//! - [`AffinePoint`]
//! - [`Scalar`]
//!
//! Please see type-specific documentation for more information.
#[cfg(feature = "arithmetic")]
mod arithmetic;
#[cfg(feature = "ecdh")]
pub mod ecdh;
#[cfg(feature = "ecdsa-core")]
pub mod ecdsa;
#[cfg(any(feature = "test-vectors", test))]
pub mod test_vectors;
#[cfg(feature = "arithmetic")]
pub use arithmetic::{scalar::Scalar, AffinePoint, ProjectivePoint};
pub use elliptic_curve::{self, bigint::U576};
#[cfg(feature = "pkcs8")]
pub use elliptic_curve::pkcs8;
use elliptic_curve::{consts::U66, generic_array::GenericArray, FieldBytesEncoding};
/// NIST P-521 elliptic curve.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
pub struct NistP521;
impl elliptic_curve::Curve for NistP521 {
/// 66-byte serialized field elements.
type FieldBytesSize = U66;
/// 521-bit integer type used for internally representing field elements.
type Uint = U576;
/// Order of NIST P-521's elliptic curve group (i.e. scalar modulus).
const ORDER: U576 = U576::from_be_hex("00000000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409");
}
impl elliptic_curve::PrimeCurve for NistP521 {}
impl elliptic_curve::point::PointCompression for NistP521 {
/// NIST P-521 points are typically uncompressed.
const COMPRESS_POINTS: bool = false;
}
impl elliptic_curve::point::PointCompaction for NistP521 {
/// NIST P-521 points are typically uncompacted.
const COMPACT_POINTS: bool = false;
}
#[cfg(feature = "jwk")]
impl elliptic_curve::JwkParameters for NistP521 {
const CRV: &'static str = "P-521";
}
#[cfg(feature = "pkcs8")]
impl pkcs8::AssociatedOid for NistP521 {
const OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.3.132.0.35");
}
/// Compressed SEC1-encoded NIST P-521 curve point.
pub type CompressedPoint = GenericArray<u8, U66>;
/// NIST P-521 SEC1 encoded point.
pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint<NistP521>;
/// NIST P-521 field element serialized as bytes.
///
/// Byte array containing a serialized field element value (base field or
/// scalar).
pub type FieldBytes = elliptic_curve::FieldBytes<NistP521>;
impl FieldBytesEncoding<NistP521> for U576 {}
/// Non-zero NIST P-521 scalar field element.
#[cfg(feature = "arithmetic")]
pub type NonZeroScalar = elliptic_curve::NonZeroScalar<NistP521>;
/// NIST P-521 public key.
#[cfg(feature = "arithmetic")]
pub type PublicKey = elliptic_curve::PublicKey<NistP521>;
/// NIST P-521 secret key.
pub type SecretKey = elliptic_curve::SecretKey<NistP521>;
#[cfg(feature = "voprf")]
impl elliptic_curve::VoprfParameters for NistP521 {
/// See <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#section-4.5-1>.
const ID: &'static str = "P521-SHA512";
/// See <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4.5-1.2>.
type Hash = sha2::Sha512;
}

5
vendor/p521/src/test_vectors.rs vendored Normal file
View File

@@ -0,0 +1,5 @@
//! secp521r1 test vectors.
#[cfg(test)]
pub mod ecdsa;
pub mod group;

Binary file not shown.

151
vendor/p521/src/test_vectors/ecdsa.rs vendored Normal file
View File

@@ -0,0 +1,151 @@
//! ECDSA/secp224r1 test vectors
use ecdsa_core::dev::TestVector;
use hex_literal::hex;
/// ECDSA/P-521 test vectors.
///
/// Adapted from the FIPS 186-4 ECDSA test vectors
/// (P-521, SHA-521, from `SigGen.txt` in `186-4ecdsatestvectors.zip`)
/// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/digital-signatures>
///
/// The `m` field contains a SHA-512 prehash of the `Msg` field in the
/// original `SigTen.txt`.
pub const ECDSA_TEST_VECTORS: &[TestVector] = &[
TestVector {
m: &hex!("000065f83408092261bda599389df03382c5be01a81fe00a36f3f4bb6541263f801627c440e50809712b0cace7c217e6e5051af81de9bfec3204dcd63c4f9a741047"),
d: &hex!("00f749d32704bc533ca82cef0acf103d8f4fba67f08d2678e515ed7db886267ffaf02fab0080dca2359b72f574ccc29a0f218c8655c0cccf9fee6c5e567aa14cb926"),
q_x: &hex!("0061387fd6b95914e885f912edfbb5fb274655027f216c4091ca83e19336740fd81aedfe047f51b42bdf68161121013e0d55b117a14e4303f926c8debb77a7fdaad1"),
q_y: &hex!("00e7d0c75c38626e895ca21526b9f9fdf84dcecb93f2b233390550d2b1463b7ee3f58df7346435ff0434199583c97c665a97f12f706f2357da4b40288def888e59e6"),
k: &hex!("003af5ab6caa29a6de86a5bab9aa83c3b16a17ffcd52b5c60c769be3053cdddeac60812d12fecf46cfe1f3db9ac9dcf881fcec3f0aa733d4ecbb83c7593e864c6df1"),
r: &hex!("004de826ea704ad10bc0f7538af8a3843f284f55c8b946af9235af5af74f2b76e099e4bc72fd79d28a380f8d4b4c919ac290d248c37983ba05aea42e2dd79fdd33e8"),
s: &hex!("0087488c859a96fea266ea13bf6d114c429b163be97a57559086edb64aed4a18594b46fb9efc7fd25d8b2de8f09ca0587f54bd287299f47b2ff124aac566e8ee3b43"),
},
TestVector {
m: &hex!("0000a6200971c6a289e2fcb80f78ec08a5079ea2675efd68bcab479552aa5bcb8edf3c993c79d7cebcc23c20e5af41723052b871134cc71d5c57206182a7068cc39b"),
d: &hex!("01a4d2623a7d59c55f408331ba8d1523b94d6bf8ac83375ceb57a2b395a5bcf977cfc16234d4a97d6f6ee25a99aa5bff15ff535891bcb7ae849a583e01ac49e0e9b6"),
q_x: &hex!("004d5c8afee038984d2ea96681ec0dccb6b52dfa4ee2e2a77a23c8cf43ef19905a34d6f5d8c5cf0981ed804d89d175b17d1a63522ceb1e785c0f5a1d2f3d15e51352"),
q_y: &hex!("0014368b8e746807b2b68f3615cd78d761a464ddd7918fc8df51d225962fdf1e3dc243e265100ff0ec133359e332e44dd49afd8e5f38fe86133573432d33c02fa0a3"),
k: &hex!("00bc2c0f37155859303de6fa539a39714e195c37c6ea826e224c8218584ae09cd0d1cc14d94d93f2d83c96e4ef68517fdb3f383da5404e5a426bfc5d424e253c181b"),
r: &hex!("01a3c4a6386c4fb614fba2cb9e74201e1aaa0001aa931a2a939c92e04b8344535a20f53c6e3c69c75c2e5d2fe3549ed27e6713cb0f4a9a94f6189eb33bff7d453fce"),
s: &hex!("016a997f81aa0bea2e1469c8c1dab7df02a8b2086ba482c43af04f2174831f2b1761658795adfbdd44190a9b06fe10e578987369f3a2eced147cff89d8c2818f7471"),
},
TestVector {
m: &hex!("000046ff533622cc90321a3aeb077ec4db4fbf372c7a9db48b59de7c5d59e6314110676ba5491bd20d0f02774eef96fc2e88ca99857d21ef255184c93fb1ff4f01d3"),
d: &hex!("014787f95fb1057a2f3867b8407e54abb91740c097dac5024be92d5d65666bb16e4879f3d3904d6eab269cf5e7b632ab3c5f342108d1d4230c30165fba3a1bf1c66f"),
q_x: &hex!("00c2d540a7557f4530de35bbd94da8a6defbff783f54a65292f8f76341c996cea38795805a1b97174a9147a8644282e0d7040a6f83423ef2a0453248156393a1782e"),
q_y: &hex!("0119f746c5df8cec24e4849ac1870d0d8594c799d2ceb6c3bdf891dfbd2242e7ea24d6aec3166214734acc4cbf4da8f71e2429c5c187b2b3a048527c861f58a9b97f"),
k: &hex!("0186cd803e6e0c9925022e41cb68671adba3ead5548c2b1cd09348ab19612b7af3820fd14da5fe1d7b550ed1a3c8d2f30592cd7745a3c09ee7b5dcfa9ed31bdd0f1f"),
r: &hex!("010ed3ab6d07a15dc3376494501c27ce5f78c8a2b30cc809d3f9c3bf1aef437e590ef66abae4e49065ead1af5f752ec145acfa98329f17bca9991a199579c41f9229"),
s: &hex!("008c3457fe1f93d635bb52df9218bf3b49a7a345b8a8a988ac0a254340546752cddf02e6ce47eee58ea398fdc9130e55a4c09f5ae548c715f5bcd539f07a34034d78"),
},
TestVector {
m: &hex!("00006b514f8d85145e30ced23b4b22c85d79ed2bfcfed5b6b2b03f7c730f1981d46d4dadd6699c28627d41c8684bac305b59eb1d9c966de184ae3d7470a801c99fd4"),
d: &hex!("015807c101099c8d1d3f24b212af2c0ce525432d7779262eed0709275de9a1d8a8eeeadf2f909cf08b4720815bc1205a23ad1f825618cb78bde747acad8049ca9742"),
q_x: &hex!("0160d7ea2e128ab3fabd1a3ad5455cb45e2f977c2354a1345d4ae0c7ce4e492fb9ff958eddc2aa61735e5c1971fa6c99beda0f424a20c3ce969380aaa52ef5f5daa8"),
q_y: &hex!("014e4c83f90d196945fb4fe1e41913488aa53e24c1d2142d35a1eed69fed784c0ef44d71bc21afe0a0065b3b87069217a5abab4355cf8f4ceae5657cd4b9c8008f1f"),
k: &hex!("0096731f8c52e72ffcc095dd2ee4eec3da13c628f570dba169b4a7460ab471149abdede0b63e4f96faf57eab809c7d2f203fd5ab406c7bd79869b7fae9c62f97c794"),
r: &hex!("01e2bf98d1186d7bd3509f517c220de51c9200981e9b344b9fb0d36f34d969026c80311e7e73bb13789a99e0d59e82ebe0e9595d9747204c5f5550c30d934aa30c05"),
s: &hex!("012fed45cc874dc3ed3a11dd70f7d5c61451fbea497dd63e226e10364e0718d3722c27c7b4e5027051d54b8f2a57fc58bc070a55b1a5877b0f388d768837ef2e9cec"),
},
TestVector {
m: &hex!("000053c86e0b08b28e22131324f6bfad52984879ab09363d6b6c051aac78bf3568be3faeade6a2dda57dece4527abaa148326d3adbd2d725374bdac9ccb8ac39e51e"),
d: &hex!("018692def0b516edcdd362f42669999cf27a65482f9358fcab312c6869e22ac469b82ca9036fe123935b8b9ed064acb347227a6e377fb156ec833dab9f170c2ac697"),
q_x: &hex!("01ceee0be3293d8c0fc3e38a78df55e85e6b4bbce0b9995251f0ac55234140f82ae0a434b2bb41dc0aa5ecf950d4628f82c7f4f67651b804d55d844a02c1da6606f7"),
q_y: &hex!("01f775eb6b3c5e43fc754052d1f7fc5b99137afc15d231a0199a702fc065c917e628a54e038cbfebe05c90988b65183b368a2061e5b5c1b025bbf2b748fae00ba297"),
k: &hex!("0161cf5d37953e09e12dc0091dc35d5fb3754c5c874e474d2b4a4f1a90b870dff6d99fb156498516e25b9a6a0763170702bb8507fdba4a6131c7258f6ffc3add81fd"),
r: &hex!("014dfa43046302b81fd9a34a454dea25ccb594ace8df4f9d98556ca5076bcd44b2a9775dfaca50282b2c8988868e5a31d9eb08e794016996942088d43ad3379eb9a1"),
s: &hex!("0120be63bd97691f6258b5e78817f2dd6bf5a7bf79d01b8b1c3382860c4b00f89894c72f93a69f3119cb74c90b03e9ede27bd298b357b9616a7282d176f3899aaa24"),
},
TestVector {
m: &hex!("0000a9e9a9cb1febc380a22c03bacd18f8c46761180badd2e58b94703bd82d5987c52baec418388bc3f1e6831a130c400b3c865c51b73514f5b0a9026d9e8da2e342"),
d: &hex!("00a63f9cdefbccdd0d5c9630b309027fa139c31e39ca26686d76c22d4093a2a5e5ec4e2308ce43eb8e563187b5bd811cc6b626eace4063047ac0420c3fdcff5bdc04"),
q_x: &hex!("014cab9759d4487987b8a00afd16d7199585b730fb0bfe63796272dde9135e7cb9e27cec51207c876d9214214b8c76f82e7363f5086902a577e1c50b4fbf35ce9966"),
q_y: &hex!("01a83f0caa01ca2166e1206292342f47f358009e8b891d3cb817aec290e0cf2f47e7fc637e39dca03949391839684f76b94d34e5abc7bb750cb44486cce525eb0093"),
k: &hex!("001e51fd877dbbcd2ab138fd215d508879298d10c7fcbdcc918802407088eb6ca0f18976a13f2c0a57867b0298512fc85515b209c4435e9ef30ab01ba649838bc7a0"),
r: &hex!("011a1323f6132d85482d9b0f73be838d8f9e78647934f2570fededca7c234cc46aa1b97da5ac1b27b714f7a171dc4209cbb0d90e4f793c4c192dc039c31310d6d99b"),
s: &hex!("00386a5a0fc55d36ca7231a9537fee6b9e51c2255363d9c9e7cb7185669b302660e23133eb21eb56d305d36e69a79f5b6fa25b46ec61b7f699e1e9e927fb0bceca06"),
},
TestVector {
m: &hex!("00007e324819033de8f2bffded5472853c3e68f4872ed25db79636249aecc24242cc3ca229ce7bd6d74eac8ba32f779e7002095f5d452d0bf24b30e1ce2eb56bb413"),
d: &hex!("0024f7d67dfc0d43a26cc7c19cb511d30a097a1e27e5efe29e9e76e43849af170fd9ad57d5b22b1c8840b59ebf562371871e12d2c1baefc1abaedc872ed5d2666ad6"),
q_x: &hex!("009da1536154b46e3169265ccba2b4da9b4b06a7462a067c6909f6c0dd8e19a7bc2ac1a47763ec4be06c1bec57d28c55ee936cb19588cc1398fe4ea3bd07e6676b7f"),
q_y: &hex!("014150cdf25da0925926422e1fd4dcfcffb05bdf8682c54d67a9bd438d21de5af43a15d979b320a847683b6d12ac1383a7183095e9da491c3b4a7c28874625e70f87"),
k: &hex!("01c1308f31716d85294b3b5f1dc87d616093b7654907f55289499b419f38ceeb906d2c9fe4cc3d80c5a38c53f9739311b0b198111fede72ebde3b0d2bc4c2ef090d2"),
r: &hex!("000dbf787ce07c453c6c6a67b0bf6850c8d6ca693a3e9818d7453487844c9048a7a2e48ff982b64eb9712461b26b5127c4dc57f9a6ad1e15d8cd56d4fd6da7186429"),
s: &hex!("00c6f1c7774caf198fc189beb7e21ca92ceccc3f9875f0e2d07dc1d15bcc8f210b6dd376bf65bb6a454bf563d7f563c1041d62d6078828a57538b25ba54723170665"),
},
TestVector {
m: &hex!("00004541f9a04b289cd3b13d31d2f513d9243b7e8c3a0cbd3e0c790892235a4d4569ef8aef62444ecc64608509e6ad082bf7cd060d172550faa158b2fd396aa1e37b"),
d: &hex!("00349471460c205d836aa37dcd6c7322809e4e8ef81501e5da87284b267d843897746b33016f50a7b702964910361ed51d0afd9d8559a47f0b7c25b2bc952ce8ed9e"),
q_x: &hex!("000bbd4e8a016b0c254e754f68f0f4ed081320d529ecdc7899cfb5a67dd04bc85b3aa6891a3ed2c9861ae76c3847d81780c23ad84153ea2042d7fd5d517a26ff3ce4"),
q_y: &hex!("00645953afc3c1b3b74fdf503e7d3f982d7ee17611d60f8eb42a4bddbec2b67db1f09b54440c30b44e8071d404658285cb571462001218fc8c5e5b98b9fae28272e6"),
k: &hex!("000eb2bd8bb56b9d2e97c51247baf734cc655c39e0bfda35375f0ac2fe82fad699bf1989577e24afb33c3868f91111e24fefe7dec802f3323ac013bec6c048fe5568"),
r: &hex!("014bf63bdbc014aa352544bd1e83ede484807ed760619fa6bc38c4f8640840195e1f2f149b29903ca4b6934404fb1f7de5e39b1ea04dba42819c75dbef6a93ebe269"),
s: &hex!("005d1bcf2295240ce4415042306abd494b4bda7cf36f2ee2931518d2454faa01c606be120b057062f2f3a174cb09c14f57ab6ef41cb3802140da22074d0e46f908d4"),
},
TestVector {
m: &hex!("00007ec0906f9fbe0e001460852c0b6111b1cd01c9306c0c57a5e746d43f48f50ebb111551d04a90255b22690d79ea60e58bed88220d485daaf9b6431740bb499e39"),
d: &hex!("007788d34758b20efc330c67483be3999d1d1a16fd0da81ed28895ebb35ee21093d37ea1ac808946c275c44454a216195eb3eb3aea1b53a329eca4eb82dd48c784f5"),
q_x: &hex!("00157d80bd426f6c3cee903c24b73faa02e758607c3e102d6e643b7269c299684fdaba1acddb83ee686a60acca53cddb2fe976149205c8b8ab6ad1458bc00993cc43"),
q_y: &hex!("016e33cbed05721b284dacc8c8fbe2d118c347fc2e2670e691d5d53daf6ef2dfec464a5fbf46f8efce81ac226915e11d43c11c8229fca2327815e1f8da5fe95021fc"),
k: &hex!("00a73477264a9cc69d359464abb1ac098a18c0fb3ea35e4f2e6e1b060dab05bef1255d9f9c9b9fbb89712e5afe13745ae6fd5917a9aedb0f2860d03a0d8f113ea10c"),
r: &hex!("007e315d8d958b8ce27eaf4f3782294341d2a46fb1457a60eb9fe93a9ae86f3764716c4f5f124bd6b114781ed59c3f24e18aa35c903211b2f2039d85862932987d68"),
s: &hex!("01bcc1d211ebc120a97d465b603a1bb1e470109e0a55d2f1b5c597803931bd6d7718f010d7d289b31533e9fcef3d141974e5955bc7f0ee342b9cad05e29a3dded30e"),
},
TestVector {
m: &hex!("00007230642b79eed2fd50f19f79f943d67d6ef609ec06c9adbb4b0a62126926080ecd474922d1af6c01f4c354affde016b284b13dbb3122555dea2a2e6ca2a357dc"),
d: &hex!("01f98696772221e6cccd5569ed8aed3c435ee86a04689c7a64d20c30f6fe1c59cc10c6d2910261d30c3b96117a669e19cfe5b696b68feeacf61f6a3dea55e6e5837a"),
q_x: &hex!("007002872c200e16d57e8e53f7bce6e9a7832c387f6f9c29c6b75526262c57bc2b56d63e9558c5761c1d62708357f586d3aab41c6a7ca3bf6c32d9c3ca40f9a2796a"),
q_y: &hex!("01fe3e52472ef224fb38d5a0a14875b52c2f50b82b99eea98d826c77e6a9ccf798de5ffa92a0d65965f740c702a3027be66b9c844f1b2e96c134eb3fdf3edddcf11c"),
k: &hex!("01a277cf0414c6adb621d1cc0311ec908401ce040c6687ed45a0cdf2910c42c9f1954a4572d8e659733d5e26cbd35e3260be40017b2f5d38ec42315f5c0b056c596d"),
r: &hex!("00d732ba8b3e9c9e0a495249e152e5bee69d94e9ff012d001b140d4b5d082aa9df77e10b65f115a594a50114722db42fa5fbe457c5bd05e7ac7ee510aa68fe7b1e7f"),
s: &hex!("0134ac5e1ee339727df80c35ff5b2891596dd14d6cfd137bafd50ab98e2c1ab4008a0bd03552618d217912a9ec502a902f2353e757c3b5776309f7f2cfebf913e9cd"),
},
TestVector {
m: &hex!("0000d209f43006e29ada2b9fe840afdf5fe6b0abeeef5662acf3fbca7e6d1bf4538f7e860332ef6122020e70104b541c30c3c0581e2b1daa0d767271769d0f073133"),
d: &hex!("013c3852a6bc8825b45fd7da1754078913d77f4e586216a6eb08b6f03adce7464f5dbc2bea0eb7b12d103870ef045f53d67e3600d7eba07aac5db03f71b64db1cceb"),
q_x: &hex!("00c97a4ebcbbe701c9f7be127e87079edf479b76d3c14bfbee693e1638e5bff8d4705ac0c14597529dbe13356ca85eb03a418edfe144ce6cbf3533016d4efc29dbd4"),
q_y: &hex!("011c75b7a8894ef64109ac2dea972e7fd5f79b75dab1bf9441a5b8b86f1dc1324426fa6cf4e7b973b44e3d0576c52e5c9edf8ce2fc18cb3c28742d44419f044667f8"),
k: &hex!("01e25b86db041f21c2503d547e2b1b655f0b99d5b6c0e1cf2bdbd8a8c6a053f5d79d78c55b4ef75bff764a74edc920b35536e3c470b6f6b8fd53898f3bbc467539ef"),
r: &hex!("01dce45ea592b34d016497882c48dc0c7afb1c8e0f81a051800d7ab8da9d237efd892207bc9401f1d30650f66af8d5349fc5b19727756270722d5a8adb0a49b72d0a"),
s: &hex!("00b79ffcdc33e028b1ab894cb751ec792a69e3011b201a76f3b878655bc31efd1c0bf3b98aea2b14f262c19d142e008b98e890ebbf464d3b025764dd2f73c4251b1a"),
},
TestVector {
m: &hex!("0000c992314e8d282d10554b2e6e8769e8b10f85686cccafb30e7db62beaad080e0da6b5cf7cd1fc5614df56705fb1a841987cb950101e2f66d55f3a285fc75829ff"),
d: &hex!("01654eaa1f6eec7159ee2d36fb24d15d6d33a128f36c52e2437f7d1b5a44ea4fa965c0a26d0066f92c8b82bd136491e929686c8bde61b7c704daab54ed1e1bdf6b77"),
q_x: &hex!("01f269692c47a55242bb08731ff920f4915bfcecf4d4431a8b487c90d08565272c52ca90c47397f7604bc643982e34d05178e979c2cff7ea1b9eaec18d69ca7382de"),
q_y: &hex!("00750bdd866fba3e92c29599c002ac6f9e2bf39af8521b7b133f70510e9918a94d3c279edec97ab75ecda95e3dd7861af84c543371c055dc74eeeff7061726818327"),
k: &hex!("01b7519becd00d750459d63a72f13318b6ac61b8c8e7077cf9415c9b4b924f35514c9c28a0fae43d06e31c670a873716156aa7bc744577d62476e038b116576a9e53"),
r: &hex!("0183bddb46c249e868ef231a1ebd85d0773bf8105a092ab7d884d677a1e9b7d6014d6358c09538a99d9dca8f36f163ac1827df420c3f9360cc66900a9737a7f756f3"),
s: &hex!("00d05ee3e64bac4e56d9d8bd511c8a43941e953cba4e5d83c0553acb87091ff54f3aad4d69d9f15e520a2551cc14f2c86bb45513fef0295e381a7635486bd3917b50"),
},
TestVector {
m: &hex!("00006e14c91db5309a075fe69f6fe8ecd663a5ba7fab14770f96b05c22e1f631cde9e086c44335a25f63d5a43ddf57da899fcedbc4a3a4350ad2edd6f70c01bb051e"),
d: &hex!("01cba5d561bf18656991eba9a1dde8bde547885ea1f0abe7f2837e569ca52f53df5e64e4a547c4f26458b5d9626ed6d702e5ab1dd585cf36a0c84f768fac946cfd4c"),
q_x: &hex!("012857c2244fa04db3b73db4847927db63cce2fa6cb22724466d3e20bc950a9250a15eafd99f236a801e5271e8f90d9e8a97f37c12f7da65bce8a2c93bcd25526205"),
q_y: &hex!("00f394e37c17d5b8e35b488fa05a607dbc74264965043a1fb60e92edc212296ae72d7d6fe2e3457e67be853664e1da64f57e44bd259076b3bb2b06a2c604fea1be9d"),
k: &hex!("00e790238796fee7b5885dc0784c7041a4cc7ca4ba757d9f7906ad1fcbab5667e3734bc2309a48047442535ff89144b518f730ff55c0c67eeb4c880c2dfd2fb60d69"),
r: &hex!("01d7ce382295a2a109064ea03f0ad8761dd60eefb9c207a20e3c5551e82ac6d2ee5922b3e9655a65ba6c359dcbf8fa843fbe87239a5c3e3eaecec0407d2fcdb687c2"),
s: &hex!("0161963a6237b8955a8a756d8df5dbd303140bb90143b1da5f07b32f9cb64733dc6316080924733f1e2c81ade9d0be71b5b95b55666026a035a93ab3004d0bc0b19f"),
},
TestVector {
m: &hex!("000026b4f562053f7aed8b7268e95eff336ac80a448fae52329d2771b138c9c7f70de936ef54158446afa72b0a27c2a73ca45dfa38a2ba2bf323d31aba499651128f"),
d: &hex!("00972e7ff25adf8a032535e5b19463cfe306b90803bf27fabc6046ae0807d2312fbab85d1da61b80b2d5d48f4e5886f27fca050b84563aee1926ae6b2564cd756d63"),
q_x: &hex!("01d7f1e9e610619daa9d2efa563610a371677fe8b58048fdc55a98a49970f6afa6649c516f9c72085ca3722aa595f45f2803402b01c832d28aac63d9941f1a25dfea"),
q_y: &hex!("01571facce3fcfe733a8eef4e8305dfe99103a370f82b3f8d75085414f2592ad44969a2ef8196c8b9809f0eca2f7ddc71c47879e3f37a40b9fecf97992b97af29721"),
k: &hex!("00517f6e4002479dc89e8cbb55b7c426d128776ca82cf81be8c1da9557178783f40e3d047db7e77867f1af030a51de470ee3128c22e9c2d642d71e4904ab5a76edfa"),
r: &hex!("01c3262a3a3fb74fa5124b71a6c7f7b7e6d56738eabaf7666b372b299b0c99ee8a16be3df88dd955de093fc8c049f76ee83a4138cee41e5fe94755d27a52ee44032f"),
s: &hex!("0072fd88bb1684c4ca9531748dfce4c161037fcd6ae5c2803b7117fb60d3db5df7df380591aaf3073a3031306b76f062dcc547ded23f6690293c34a710e7e9a226c3"),
},
TestVector {
m: &hex!("0000ea13b25b80ec89ffa649a00ce85a494892f9fb7389df56eed084d670efb020c05508ac3f04872843c92a67ee5ea02e0445dad8495cd823ca16f5510d5863002b"),
d: &hex!("01f0ec8da29295394f2f072672db014861be33bfd9f91349dad5566ff396bea055e53b1d61c8c4e5c9f6e129ed75a49f91cce1d5530ad4e78c2b793a63195eb9f0da"),
q_x: &hex!("009ec1a3761fe3958073b9647f34202c5e8ca2428d056facc4f3fedc7077fa87f1d1eb30cc74f6e3ff3d3f82df2641cea1eb3ff1529e8a3866ae2055aacec0bf68c4"),
q_y: &hex!("00bed0261b91f664c3ff53e337d8321cb988c3edc03b46754680097e5a8585245d80d0b7045c75a9c5be7f599d3b5eea08d828acb6294ae515a3df57a37f903ef62e"),
k: &hex!("00ac3b6d61ebda99e23301fa198d686a13c0832af594b289c9a55669ce6d62011384769013748b68465527a597ed6858a06a99d50493562b3a7dbcee975ad34657d8"),
r: &hex!("00cef3f4babe6f9875e5db28c27d6a197d607c3641a90f10c2cc2cb302ba658aa151dc76c507488b99f4b3c8bb404fb5c852f959273f412cbdd5e713c5e3f0e67f94"),
s: &hex!("00097ed9e005416fc944e26bcc3661a09b35c128fcccdc2742739c8a301a338dd77d9d13571612a3b9524a6164b09fe73643bbc31447ee31ef44a490843e4e7db23f"),
},
];

256
vendor/p521/src/test_vectors/group.rs vendored Normal file
View File

@@ -0,0 +1,256 @@
//! Test vectors for the secp521r1 group.
use hex_literal::hex;
/// Repeated addition of the generator.
///
/// These are the first 20 test vectors for P-521 from: <http://point-at-infinity.org/ecc/nisttv>
pub const ADD_TEST_VECTORS: &[([u8; 66], [u8; 66])] = &[
(
hex!("00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"),
hex!("011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"),
),
(
hex!("00433C219024277E7E682FCB288148C282747403279B1CCC06352C6E5505D769BE97B3B204DA6EF55507AA104A3A35C5AF41CF2FA364D60FD967F43E3933BA6D783D"),
hex!("00F4BB8CC7F86DB26700A7F3ECEEEED3F0B5C6B5107C4DA97740AB21A29906C42DBBB3E377DE9F251F6B93937FA99A3248F4EAFCBE95EDC0F4F71BE356D661F41B02"),
),
(
hex!("01A73D352443DE29195DD91D6A64B5959479B52A6E5B123D9AB9E5AD7A112D7A8DD1AD3F164A3A4832051DA6BD16B59FE21BAEB490862C32EA05A5919D2EDE37AD7D"),
hex!("013E9B03B97DFA62DDD9979F86C6CAB814F2F1557FA82A9D0317D2F8AB1FA355CEEC2E2DD4CF8DC575B02D5ACED1DEC3C70CF105C9BC93A590425F588CA1EE86C0E5"),
),
(
hex!("0035B5DF64AE2AC204C354B483487C9070CDC61C891C5FF39AFC06C5D55541D3CEAC8659E24AFE3D0750E8B88E9F078AF066A1D5025B08E5A5E2FBC87412871902F3"),
hex!("0082096F84261279D2B673E0178EB0B4ABB65521AEF6E6E32E1B5AE63FE2F19907F279F283E54BA385405224F750A95B85EEBB7FAEF04699D1D9E21F47FC346E4D0D"),
),
(
hex!("00652BF3C52927A432C73DBC3391C04EB0BF7A596EFDB53F0D24CF03DAB8F177ACE4383C0C6D5E3014237112FEAF137E79A329D7E1E6D8931738D5AB5096EC8F3078"),
hex!("015BE6EF1BDD6601D6EC8A2B73114A8112911CD8FE8E872E0051EDD817C9A0347087BB6897C9072CF374311540211CF5FF79D1F007257354F7F8173CC3E8DEB090CB"),
),
(
hex!("01EE4569D6CDB59219532EFF34F94480D195623D30977FD71CF3981506ADE4AB01525FBCCA16153F7394E0727A239531BE8C2F66E95657F380AE23731BEDF79206B9"),
hex!("01DE0255AD0CC64F586AE2DD270546E3B1112AABBB73DA5A808E7240A926201A8A96CAB72D0E56648C9DF96C984DE274F2203DC7B8B55CA0DADE1EACCD7858D44F17"),
),
(
hex!("0056D5D1D99D5B7F6346EEB65FDA0B073A0C5F22E0E8F5483228F018D2C2F7114C5D8C308D0ABFC698D8C9A6DF30DCE3BBC46F953F50FDC2619A01CEAD882816ECD4"),
hex!("003D2D1B7D9BAAA2A110D1D8317A39D68478B5C582D02824F0DD71DBD98A26CBDE556BD0F293CDEC9E2B9523A34591CE1A5F9E76712A5DDEFC7B5C6B8BC90525251B"),
),
(
hex!("000822C40FB6301F7262A8348396B010E25BD4E29D8A9B003E0A8B8A3B05F826298F5BFEA5B8579F49F08B598C1BC8D79E1AB56289B5A6F4040586F9EA54AA78CE68"),
hex!("016331911D5542FC482048FDAB6E78853B9A44F8EDE9E2C0715B5083DE610677A8F189E9C0AA5911B4BFF0BA0DF065C578699F3BA940094713538AD642F11F17801C"),
),
(
hex!("01585389E359E1E21826A2F5BF157156D488ED34541B988746992C4AB145B8C6B6657429E1396134DA35F3C556DF725A318F4F50BABD85CD28661F45627967CBE207"),
hex!("002A2E618C9A8AEDF39F0B55557A27AE938E3088A654EE1CEBB6C825BA263DDB446E0D69E5756057AC840FF56ECF4ABFD87D736C2AE928880F343AA0EA86B9AD2A4E"),
),
(
hex!("0190EB8F22BDA61F281DFCFE7BB6721EC4CD901D879AC09AC7C34A9246B11ADA8910A2C7C178FCC263299DAA4DA9842093F37C2E411F1A8E819A87FF09A04F2F3320"),
hex!("01EB5D96B8491614BA9DBAEAB3B0CA2BA760C2EEB2144251B20BA97FD78A62EF62D2BF5349D44D9864BB536F6163DC57EBEFF3689639739FAA172954BC98135EC759"),
),
(
hex!("008A75841259FDEDFF546F1A39573B4315CFED5DC7ED7C17849543EF2C54F2991652F3DBC5332663DA1BD19B1AEBE3191085015C024FA4C9A902ECC0E02DDA0CDB9A"),
hex!("0096FB303FCBBA2129849D0CA877054FB2293ADD566210BD0493ED2E95D4E0B9B82B1BC8A90E8B42A4AB3892331914A95336DCAC80E3F4819B5D58874F92CE48C808"),
),
(
hex!("01C0D9DCEC93F8221C5DE4FAE9749C7FDE1E81874157958457B6107CF7A5967713A644E90B7C3FB81B31477FEE9A60E938013774C75C530928B17BE69571BF842D8C"),
hex!("014048B5946A4927C0FE3CE1D103A682CA4763FE65AB71494DA45E404ABF6A17C097D6D18843D86FCDB6CC10A6F951B9B630884BA72224F5AE6C79E7B1A3281B17F0"),
),
(
hex!("007E3E98F984C396AD9CD7865D2B4924861A93F736CDE1B4C2384EEDD2BEAF5B866132C45908E03C996A3550A5E79AB88EE94BEC3B00AB38EFF81887848D32FBCDA7"),
hex!("0108EE58EB6D781FEDA91A1926DAA3ED5A08CED50A386D5421C69C7A67AE5C1E212AC1BD5D5838BC763F26DFDD351CBFBBC36199EAAF9117E9F7291A01FB022A71C9"),
),
(
hex!("01875BC7DC551B1B65A9E1B8CCFAAF84DED1958B401494116A2FD4FB0BABE0B3199974FC06C8B897222D79DF3E4B7BC744AA6767F6B812EFBF5D2C9E682DD3432D74"),
hex!("005CA4923575DACB5BD2D66290BBABB4BDFB8470122B8E51826A0847CE9B86D7ED62D07781B1B4F3584C11E89BF1D133DC0D5B690F53A87C84BE41669F852700D54A"),
),
(
hex!("006B6AD89ABCB92465F041558FC546D4300FB8FBCC30B40A0852D697B532DF128E11B91CCE27DBD00FFE7875BD1C8FC0331D9B8D96981E3F92BDE9AFE337BCB8DB55"),
hex!("01B468DA271571391D6A7CE64D2333EDBF63DF0496A9BAD20CBA4B62106997485ED57E9062C899470A802148E2232C96C99246FD90CC446ABDD956343480A1475465"),
),
(
hex!("01D17D10D8A89C8AD05DDA97DA26AC743B0B2A87F66192FD3F3DD632F8D20B188A52943FF18861CA00A0E5965DA7985630DF0DBF5C8007DCDC533A6C508F81A8402F"),
hex!("007A37343C582D77001FC714B18D3D3E69721335E4C3B800D50EC7CA30C94B6B82C1C182E1398DB547AA0B3075AC9D9988529E3004D28D18633352E272F89BC73ABE"),
),
(
hex!("01B00DDB707F130EDA13A0B874645923906A99EE9E269FA2B3B4D66524F269250858760A69E674FE0287DF4E799B5681380FF8C3042AF0D1A41076F817A853110AE0"),
hex!("0085683F1D7DB16576DBC111D4E4AEDDD106B799534CF69910A98D68AC2B22A1323DF9DA564EF6DD0BF0D2F6757F16ADF420E6905594C2B755F535B9CB7C70E64647"),
),
(
hex!("01BC33425E72A12779EACB2EDCC5B63D1281F7E86DBC7BF99A7ABD0CFE367DE4666D6EDBB8525BFFE5222F0702C3096DEC0884CE572F5A15C423FDF44D01DD99C61D"),
hex!("010D06E999885B63535DE3E74D33D9E63D024FB07CE0D196F2552C8E4A00AC84C044234AEB201F7A9133915D1B4B45209B9DA79FE15B19F84FD135D841E2D8F9A86A"),
),
(
hex!("00998DCCE486419C3487C0F948C2D5A1A07245B77E0755DF547EFFF0ACDB3790E7F1FA3B3096362669679232557D7A45970DFECF431E725BBDE478FF0B2418D6A19B"),
hex!("0137D5DA0626A021ED5CC3942497535B245D67D28AEE2B7BCF4ACC50EEE36545772773AD963FF2EB8CF9B0EC39991631C377F5A4D89EA9FBFE44A9091A695BFD0575"),
),
(
hex!("018BDD7F1B889598A4653DEEAE39CC6F8CC2BD767C2AB0D93FB12E968FBED342B51709506339CB1049CB11DD48B9BDB3CD5CAD792E43B74E16D8E2603BFB11B0344F"),
hex!("00C5AADBE63F68CA5B6B6908296959BF0AF89EE7F52B410B9444546C550952D311204DA3BDDDC6D4EAE7EDFAEC1030DA8EF837CCB22EEE9CFC94DD3287FED0990F94"),
)
];
/// Scalar multiplication with the generator.
///
/// These are the test vectors for P-521 from <http://point-at-infinity.org/ecc/nisttv>
/// that are not part of [`ADD_TEST_VECTORS`].
pub const MUL_TEST_VECTORS: &[([u8; 66], [u8; 66], [u8; 66])] = &[
(
hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018ebbb95eed0e13"),
hex!("01650048FBD63E8C30B305BF36BD7643B91448EF2206E8A0CA84A140789A99B0423A0A2533EA079CA7E049843E69E5FA2C25A163819110CEC1A30ACBBB3A422A40D8"),
hex!("010C9C64A0E0DB6052DBC5646687D06DECE5E9E0703153EFE9CB816FE025E85354D3C5F869D6DB3F4C0C01B5F97919A5E72CEEBE03042E5AA99112691CFFC2724828"),
),
(
hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000159d893d4cdd747246cdca43590e13"),
hex!("017E1370D39C9C63925DAEEAC571E21CAAF60BD169191BAEE8352E0F54674443B29786243564ABB705F6FC0FE5FC5D3F98086B67CA0BE7AC8A9DEC421D9F1BC6B37F"),
hex!("01CD559605EAD19FBD99E83600A6A81A0489E6F20306EE0789AE00CE16A6EFEA2F42F7534186CF1C60DF230BD9BCF8CB95E5028AD9820B2B1C0E15597EE54C4614A6"),
),
(
hex!("0083ff83fffffc03fff80007fffc000f8003ffe00007ffe0fffc000f8000000007ffffff00ffff000ffffff001fffc000000001c0000400000003803ffffffcfffff"),
hex!("00B45CB84651C9D4F08858B867F82D816E84E94FE4CAE3DA5F65E420B08398D0C5BF019253A6C26D20671BDEF0B8E6C1D348A4B0734687F73AC6A4CBB2E085C68B3F"),
hex!("01C84942BBF538903062170A4BA8B3410D385719BA2037D29CA5248BFCBC8478220FEC79244DCD45D31885A1764DEE479CE20B12CEAB62F9001C7AA4282CE4BE7F56"),
),
(
hex!("000001ffffe03ffff1ffff801fffffffff8000001fffff800ffffff8001fffc7ffff820000040007ffffe000001f800007fffffffc00001c007c0007000070000007"),
hex!("01CCEF4CDA108CEBE6568820B54A3CA3A3997E4EF0EDA6C350E7ED3DBB1861EDD80181C650CEBE5440FEBA880F9C8A7A86F8B82659794F6F5B88E501E5DD84E65D7E"),
hex!("01026565F8B195D03C3F6139C3A63EAA1C29F7090AB2A8F75027939EC05109035F1B38E6C508E0C14CE53AB7E2DA33AA28140EDBF3964862FB157119517454E60F07"),
),
(
hex!("00007fffffe0003f00000007f00007ffff80000000001ffc000000fff030001f0000fffff0000038000000000002003f007ffffff0000000000000ffe00000000000"),
hex!("00C1002DC2884EEDADB3F9B468BBEBD55980799852C506D37271FFCD006919DB3A96DF8FE91EF6ED4B9081B1809E8F2C2B28AF5FCBF524147C73CB0B913D6FAB0995"),
hex!("01614E8A62C8293DD2AA6EF27D30974A4FD185019FA8EF4F982DA48698CECF706581F69EE9ED67A9C231EC9D0934D0F674646153273BCBB345E923B1EC1386A1A4AD"),
),
(
hex!("00001fffc1000003fe0003ffffffe0001ffffffffffffff00001fffff83ffffffffffffe003ffffffffffff7ffffc03ff807fffe0001fffff800fff800001ffff000"),
hex!("010ED3E085ECDE1E66874286B5D5642B9D37853A026A0A025C7B84936E2ECEEC5F342E14C80C79CCF814D5AD085C5303F2823251F2B9276F88C9D7A43E387EBD87AC"),
hex!("01BE399A7666B29E79BBF3D277531A97CE05CAC0B49BECE4781E7AEE0D6E80FEE883C76E9F08453DC1ADE4E49300F3D56FEE6A1510DA1B1F12EEAA39A05AA0508119"),
),
(
hex!("000000000fff80fffffffe03fffc07fffc800070000fc0007ffc00000000000fffe1fbff81ff9fffff81fff81fc000000000ff801fffc0f81f01fff8001fc005ffff"),
hex!("013070A29B059D317AF37089E40FCB135868F52290EFF3E9F3E32CDADCA18EA234D8589C665A4B8E3D0714DE004A419DEA7091A3BBA97263C438FE9413AA598FD4A5"),
hex!("00238A27FD9E5E7324C8B538EF2E334B71AC2611A95F42F4F2544D8C4A65D2A32A8BAFA15EFD4FC2BD8AB2B0C51F65B680879589F4D5FE8A84CEB17A2E8D3587F011"),
),
(
hex!("000fffffc01ffffff01fffffe000000fc0ffffff00063ffdffbffff87ffffffffe03fffffffff0000000000ff8001f8000000008007ff800003ffff00000fffc01ff"),
hex!("01A3D88799878EC74E66FF1AD8C7DFA9A9B4445A17F0810FF8189DD27AE3B6C580D352476DBDAEB08D7DA0DE3866F7C7FDBEBB8418E19710F1F7AFA88C22280B1404"),
hex!("00B39703D2053EC7B8812BDFEBFD81B4CB76F245FE535A1F1E46801C35DE03C15063A99A203981529C146132863CA0E68544D0F0A638D8A2859D82B4DD266F27C3AE"),
),
(
hex!("000000003ffe001ffffffc7ffe00000000fffbff00000007ffe00ffffff803ffffff3ffffc003f8000000007fe03ff8000fff8007ffffffffc0003ffe0001fc0000f"),
hex!("01D16B4365DEFE6FD356DC1F31727AF2A32C7E86C5AE87ED2950A08BC8653F203C7F7860E80F95AA27C93EA76E8CD094127B15ED42CC5F96DC0A0F9A1C1E31D0D526"),
hex!("006E3710A0F9366E0BB8A14FFE8EBC2722EECF4A123EC9BA98DCCCA335D6FAFD289DC69FD90903C9AC982FEB46DF93F03A7C8C9549D32C1C386D17F37340E63822A8"),
),
(
hex!("00007f0000003ffc00000001fff007fff008000000ff0000000fffc03fffffff800000030fff80fe00000000c00001ffff8001ffffffffe0000000000003fffffff3"),
hex!("01B1220F67C985E9FC9C588C0C86BB16E6FE4CC11E168A98D701AE4670724B3D030ED9965FADF4207C7A1BE9BE0F40DEF2BBFFF0C7EABCB5B42526CE1D3CAA468F52"),
hex!("006CDAD2860F6D2C37159A5A866D11605F2E7D87430DCFE6E6816AB6423CD9003CA6F2527B9C2A2483C541D456C963D18A0D2A46E158CB2A44C0BF42D562881FB748"),
),
(
hex!("00f07f80ffffff00003ff8003ff87fffff007fe07e0000003ffffff80007fe0000000000000003fc00000000007ffc07ff807f7f1fffef07fffff8000000000003ff"),
hex!("00F25E545213C8C074BE38A0612EA9B66336B14A874372548D9716392DFA31CD0D13E94F86CD48B8D43B80B5299144E01245C873B39F6AC6C4FB397746AF034AD67C"),
hex!("01733ABB21147CC27E35F41FAF40290AFD1EEB221D983FFABBD88E5DC8776450A409EACDC1BCA2B9F517289C68645BB96781808FEAE42573C2BB289F16E2AECECE17"),
),
(
hex!("000000000003fff7ffffffffffffffe007ffffffe3fffffffffc01ffe0001fe01fffffff0000000000ffffffc0000000007ffffff03ff8000000000000c000000000"),
hex!("0172CD22CBE0634B6BFEE24BB1D350F384A945ED618ECAD48AADC6C1BC0DCC107F0FFE9FE14DC929F90153F390C25BE5D3A73A56F9ACCB0C72C768753869732D0DC4"),
hex!("00D249CFB570DA4CC48FB5426A928B43D7922F787373B6182408FBC71706E7527E8414C79167F3C999FF58DE352D238F1FE7168C658D338F72696F2F889A97DE23C5"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f5"),
hex!("018BDD7F1B889598A4653DEEAE39CC6F8CC2BD767C2AB0D93FB12E968FBED342B51709506339CB1049CB11DD48B9BDB3CD5CAD792E43B74E16D8E2603BFB11B0344F"),
hex!("013A552419C09735A49496F7D696A640F50761180AD4BEF46BBBAB93AAF6AD2CEEDFB25C4222392B1518120513EFCF257107C8334DD11163036B22CD78012F66F06B"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f6"),
hex!("00998DCCE486419C3487C0F948C2D5A1A07245B77E0755DF547EFFF0ACDB3790E7F1FA3B3096362669679232557D7A45970DFECF431E725BBDE478FF0B2418D6A19B"),
hex!("00C82A25F9D95FDE12A33C6BDB68ACA4DBA2982D7511D48430B533AF111C9ABA88D88C5269C00D1473064F13C666E9CE3C880A5B2761560401BB56F6E596A402FA8A"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f7"),
hex!("01BC33425E72A12779EACB2EDCC5B63D1281F7E86DBC7BF99A7ABD0CFE367DE4666D6EDBB8525BFFE5222F0702C3096DEC0884CE572F5A15C423FDF44D01DD99C61D"),
hex!("00F2F9166677A49CACA21C18B2CC2619C2FDB04F831F2E690DAAD371B5FF537B3FBBDCB514DFE0856ECC6EA2E4B4BADF646258601EA4E607B02ECA27BE1D27065795"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f8"),
hex!("01B00DDB707F130EDA13A0B874645923906A99EE9E269FA2B3B4D66524F269250858760A69E674FE0287DF4E799B5681380FF8C3042AF0D1A41076F817A853110AE0"),
hex!("017A97C0E2824E9A89243EEE2B1B51222EF94866ACB30966EF56729753D4DD5ECDC20625A9B10922F40F2D098A80E9520BDF196FAA6B3D48AA0ACA4634838F19B9B8"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f9"),
hex!("01D17D10D8A89C8AD05DDA97DA26AC743B0B2A87F66192FD3F3DD632F8D20B188A52943FF18861CA00A0E5965DA7985630DF0DBF5C8007DCDC533A6C508F81A8402F"),
hex!("0185C8CBC3A7D288FFE038EB4E72C2C1968DECCA1B3C47FF2AF13835CF36B4947D3E3E7D1EC6724AB855F4CF8A53626677AD61CFFB2D72E79CCCAD1D8D076438C541"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863fa"),
hex!("006B6AD89ABCB92465F041558FC546D4300FB8FBCC30B40A0852D697B532DF128E11B91CCE27DBD00FFE7875BD1C8FC0331D9B8D96981E3F92BDE9AFE337BCB8DB55"),
hex!("004B9725D8EA8EC6E2958319B2DCCC12409C20FB6956452DF345B49DEF9668B7A12A816F9D3766B8F57FDEB71DDCD369366DB9026F33BB954226A9CBCB7F5EB8AB9A"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863fb"),
hex!("01875BC7DC551B1B65A9E1B8CCFAAF84DED1958B401494116A2FD4FB0BABE0B3199974FC06C8B897222D79DF3E4B7BC744AA6767F6B812EFBF5D2C9E682DD3432D74"),
hex!("01A35B6DCA8A2534A42D299D6F44544B42047B8FEDD471AE7D95F7B831647928129D2F887E4E4B0CA7B3EE17640E2ECC23F2A496F0AC57837B41BE99607AD8FF2AB5"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863fc"),
hex!("007E3E98F984C396AD9CD7865D2B4924861A93F736CDE1B4C2384EEDD2BEAF5B866132C45908E03C996A3550A5E79AB88EE94BEC3B00AB38EFF81887848D32FBCDA7"),
hex!("00F711A7149287E01256E5E6D9255C12A5F7312AF5C792ABDE3963859851A3E1DED53E42A2A7C74389C0D92022CAE340443C9E6615506EE81608D6E5FE04FDD58E36"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863fd"),
hex!("01C0D9DCEC93F8221C5DE4FAE9749C7FDE1E81874157958457B6107CF7A5967713A644E90B7C3FB81B31477FEE9A60E938013774C75C530928B17BE69571BF842D8C"),
hex!("00BFB74A6B95B6D83F01C31E2EFC597D35B89C019A548EB6B25BA1BFB54095E83F68292E77BC2790324933EF5906AE4649CF77B458DDDB0A519386184E5CD7E4E80F"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863fe"),
hex!("008A75841259FDEDFF546F1A39573B4315CFED5DC7ED7C17849543EF2C54F2991652F3DBC5332663DA1BD19B1AEBE3191085015C024FA4C9A902ECC0E02DDA0CDB9A"),
hex!("016904CFC03445DED67B62F35788FAB04DD6C522A99DEF42FB6C12D16A2B1F4647D4E43756F174BD5B54C76DCCE6EB56ACC923537F1C0B7E64A2A778B06D31B737F7"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863ff"),
hex!("0190EB8F22BDA61F281DFCFE7BB6721EC4CD901D879AC09AC7C34A9246B11ADA8910A2C7C178FCC263299DAA4DA9842093F37C2E411F1A8E819A87FF09A04F2F3320"),
hex!("0014A26947B6E9EB456245154C4F35D4589F3D114DEBBDAE4DF4568028759D109D2D40ACB62BB2679B44AC909E9C23A814100C9769C68C6055E8D6AB4367ECA138A6"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386400"),
hex!("01585389E359E1E21826A2F5BF157156D488ED34541B988746992C4AB145B8C6B6657429E1396134DA35F3C556DF725A318F4F50BABD85CD28661F45627967CBE207"),
hex!("01D5D19E736575120C60F4AAAA85D8516C71CF7759AB11E3144937DA45D9C224BB91F2961A8A9FA8537BF00A9130B54027828C93D516D777F0CBC55F15794652D5B1"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386401"),
hex!("000822C40FB6301F7262A8348396B010E25BD4E29D8A9B003E0A8B8A3B05F826298F5BFEA5B8579F49F08B598C1BC8D79E1AB56289B5A6F4040586F9EA54AA78CE68"),
hex!("009CCE6EE2AABD03B7DFB7025491877AC465BB0712161D3F8EA4AF7C219EF988570E76163F55A6EE4B400F45F20F9A3A879660C456BFF6B8ECAC7529BD0EE0E87FE3"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386402"),
hex!("0056D5D1D99D5B7F6346EEB65FDA0B073A0C5F22E0E8F5483228F018D2C2F7114C5D8C308D0ABFC698D8C9A6DF30DCE3BBC46F953F50FDC2619A01CEAD882816ECD4"),
hex!("01C2D2E48264555D5EEF2E27CE85C6297B874A3A7D2FD7DB0F228E242675D93421AA942F0D6C321361D46ADC5CBA6E31E5A061898ED5A2210384A3947436FADADAE4"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386403"),
hex!("01EE4569D6CDB59219532EFF34F94480D195623D30977FD71CF3981506ADE4AB01525FBCCA16153F7394E0727A239531BE8C2F66E95657F380AE23731BEDF79206B9"),
hex!("0021FDAA52F339B0A7951D22D8FAB91C4EEED554448C25A57F718DBF56D9DFE575693548D2F1A99B7362069367B21D8B0DDFC238474AA35F2521E1533287A72BB0E8"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386404"),
hex!("00652BF3C52927A432C73DBC3391C04EB0BF7A596EFDB53F0D24CF03DAB8F177ACE4383C0C6D5E3014237112FEAF137E79A329D7E1E6D8931738D5AB5096EC8F3078"),
hex!("00A41910E42299FE291375D48CEEB57EED6EE327017178D1FFAE1227E8365FCB8F7844976836F8D30C8BCEEABFDEE30A00862E0FF8DA8CAB0807E8C33C17214F6F34"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386405"),
hex!("0035B5DF64AE2AC204C354B483487C9070CDC61C891C5FF39AFC06C5D55541D3CEAC8659E24AFE3D0750E8B88E9F078AF066A1D5025B08E5A5E2FBC87412871902F3"),
hex!("017DF6907BD9ED862D498C1FE8714F4B5449AADE5109191CD1E4A519C01D0E66F80D860D7C1AB45C7ABFADDB08AF56A47A114480510FB9662E261DE0B803CB91B2F2"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406"),
hex!("01A73D352443DE29195DD91D6A64B5959479B52A6E5B123D9AB9E5AD7A112D7A8DD1AD3F164A3A4832051DA6BD16B59FE21BAEB490862C32EA05A5919D2EDE37AD7D"),
hex!("00C164FC4682059D2226686079393547EB0D0EAA8057D562FCE82D0754E05CAA3113D1D22B30723A8A4FD2A5312E213C38F30EFA36436C5A6FBDA0A7735E11793F1A"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386407"),
hex!("00433C219024277E7E682FCB288148C282747403279B1CCC06352C6E5505D769BE97B3B204DA6EF55507AA104A3A35C5AF41CF2FA364D60FD967F43E3933BA6D783D"),
hex!("010B44733807924D98FF580C1311112C0F4A394AEF83B25688BF54DE5D66F93BD2444C1C882160DAE0946C6C805665CDB70B1503416A123F0B08E41CA9299E0BE4FD"),
),
(
hex!("01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386408"),
hex!("00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"),
hex!("00E7C6D6958765C43FFBA375A04BD382E426670ABBB6A864BB97E85042E8D8C199D368118D66A10BD9BF3AAF46FEC052F89ECAC38F795D8D3DBF77416B89602E99AF"),
)
];