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

86
vendor/elliptic-curve/src/arithmetic.rs vendored Normal file
View File

@@ -0,0 +1,86 @@
//! Elliptic curve arithmetic traits.
use crate::{
ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign},
point::AffineCoordinates,
scalar::{FromUintUnchecked, IsHigh},
Curve, FieldBytes, PrimeCurve, ScalarPrimitive,
};
use core::fmt::Debug;
use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption};
use zeroize::DefaultIsZeroes;
/// Elliptic curve with an arithmetic implementation.
pub trait CurveArithmetic: Curve {
/// Elliptic curve point in affine coordinates.
type AffinePoint: 'static
+ AffineCoordinates<FieldRepr = FieldBytes<Self>>
+ Copy
+ ConditionallySelectable
+ ConstantTimeEq
+ Debug
+ Default
+ DefaultIsZeroes
+ Eq
+ PartialEq
+ Sized
+ Send
+ Sync;
/// Elliptic curve point in projective coordinates.
///
/// Note: the following bounds are provided by [`group::Group`]:
/// - `'static`
/// - [`Copy`]
/// - [`Clone`]
/// - [`Debug`]
/// - [`Eq`]
/// - [`Sized`]
/// - [`Send`]
/// - [`Sync`]
type ProjectivePoint: ConditionallySelectable
+ ConstantTimeEq
+ Default
+ DefaultIsZeroes
+ From<Self::AffinePoint>
+ Into<Self::AffinePoint>
+ LinearCombination
+ MulByGenerator
+ group::Curve<AffineRepr = Self::AffinePoint>
+ group::Group<Scalar = Self::Scalar>;
/// Scalar field modulo this curve's order.
///
/// Note: the following bounds are provided by [`ff::Field`]:
/// - `'static`
/// - [`Copy`]
/// - [`Clone`]
/// - [`ConditionallySelectable`]
/// - [`ConstantTimeEq`]
/// - [`Debug`]
/// - [`Default`]
/// - [`Send`]
/// - [`Sync`]
type Scalar: AsRef<Self::Scalar>
+ DefaultIsZeroes
+ From<ScalarPrimitive<Self>>
+ FromUintUnchecked<Uint = Self::Uint>
+ Into<FieldBytes<Self>>
+ Into<ScalarPrimitive<Self>>
+ Into<Self::Uint>
+ Invert<Output = CtOption<Self::Scalar>>
+ IsHigh
+ PartialOrd
+ Reduce<Self::Uint, Bytes = FieldBytes<Self>>
+ ShrAssign<usize>
+ ff::Field
+ ff::PrimeField<Repr = FieldBytes<Self>>;
}
/// Prime order elliptic curve with projective arithmetic implementation.
pub trait PrimeCurveArithmetic:
PrimeCurve + CurveArithmetic<ProjectivePoint = Self::CurveGroup>
{
/// Prime order elliptic curve group.
type CurveGroup: group::prime::PrimeCurve<Affine = <Self as CurveArithmetic>::AffinePoint>;
}

843
vendor/elliptic-curve/src/dev.rs vendored Normal file
View File

@@ -0,0 +1,843 @@
//! Development-related functionality.
//!
//! Helpers and types for writing tests against concrete implementations of
//! the traits in this crate.
use crate::{
bigint::{Limb, U256},
error::{Error, Result},
generic_array::typenum::U32,
ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign},
pkcs8,
point::AffineCoordinates,
rand_core::RngCore,
scalar::{FromUintUnchecked, IsHigh},
sec1::{CompressedPoint, FromEncodedPoint, ToEncodedPoint},
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
zeroize::DefaultIsZeroes,
Curve, CurveArithmetic, FieldBytesEncoding, PrimeCurve,
};
use core::{
iter::{Product, Sum},
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use ff::{Field, PrimeField};
use hex_literal::hex;
use pkcs8::AssociatedOid;
#[cfg(feature = "bits")]
use ff::PrimeFieldBits;
#[cfg(feature = "jwk")]
use crate::JwkParameters;
/// Pseudo-coordinate for fixed-based scalar mult output
pub const PSEUDO_COORDINATE_FIXED_BASE_MUL: [u8; 32] =
hex!("deadbeef00000000000000000000000000000000000000000000000000000001");
/// SEC1 encoded point.
pub type EncodedPoint = crate::sec1::EncodedPoint<MockCurve>;
/// Field element bytes.
pub type FieldBytes = crate::FieldBytes<MockCurve>;
/// Non-zero scalar value.
pub type NonZeroScalar = crate::NonZeroScalar<MockCurve>;
/// Public key.
pub type PublicKey = crate::PublicKey<MockCurve>;
/// Secret key.
pub type SecretKey = crate::SecretKey<MockCurve>;
/// Scalar primitive type.
// TODO(tarcieri): make this the scalar type when it's more capable
pub type ScalarPrimitive = crate::ScalarPrimitive<MockCurve>;
/// Scalar bits.
#[cfg(feature = "bits")]
pub type ScalarBits = crate::scalar::ScalarBits<MockCurve>;
/// Mock elliptic curve type useful for writing tests which require a concrete
/// curve type.
///
/// Note: this type is roughly modeled off of NIST P-256, but does not provide
/// an actual cure arithmetic implementation.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
pub struct MockCurve;
impl Curve for MockCurve {
type FieldBytesSize = U32;
type Uint = U256;
const ORDER: U256 =
U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
}
impl PrimeCurve for MockCurve {}
impl CurveArithmetic for MockCurve {
type AffinePoint = AffinePoint;
type ProjectivePoint = ProjectivePoint;
type Scalar = Scalar;
}
impl AssociatedOid for MockCurve {
/// OID for NIST P-256
const OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7");
}
#[cfg(feature = "jwk")]
impl JwkParameters for MockCurve {
const CRV: &'static str = "P-256";
}
/// Example scalar type
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
pub struct Scalar(ScalarPrimitive);
impl Field for Scalar {
const ZERO: Self = Self(ScalarPrimitive::ZERO);
const ONE: Self = Self(ScalarPrimitive::ONE);
fn random(mut rng: impl RngCore) -> Self {
let mut bytes = FieldBytes::default();
loop {
rng.fill_bytes(&mut bytes);
if let Some(scalar) = Self::from_repr(bytes).into() {
return scalar;
}
}
}
fn is_zero(&self) -> Choice {
self.0.is_zero()
}
#[must_use]
fn square(&self) -> Self {
unimplemented!();
}
#[must_use]
fn double(&self) -> Self {
self.add(self)
}
fn invert(&self) -> CtOption<Self> {
unimplemented!();
}
fn sqrt(&self) -> CtOption<Self> {
unimplemented!();
}
fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) {
unimplemented!();
}
}
impl PrimeField for Scalar {
type Repr = FieldBytes;
const MODULUS: &'static str =
"0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
const NUM_BITS: u32 = 256;
const CAPACITY: u32 = 255;
const TWO_INV: Self = Self::ZERO; // BOGUS!
const MULTIPLICATIVE_GENERATOR: Self = Self::ZERO; // BOGUS! Should be 7
const S: u32 = 4;
const ROOT_OF_UNITY: Self = Self::ZERO; // BOGUS! Should be 0xffc97f062a770992ba807ace842a3dfc1546cad004378daf0592d7fbb41e6602
const ROOT_OF_UNITY_INV: Self = Self::ZERO; // BOGUS!
const DELTA: Self = Self::ZERO; // BOGUS!
fn from_repr(bytes: FieldBytes) -> CtOption<Self> {
ScalarPrimitive::from_bytes(&bytes).map(Self)
}
fn to_repr(&self) -> FieldBytes {
self.0.to_bytes()
}
fn is_odd(&self) -> Choice {
self.0.is_odd()
}
}
#[cfg(feature = "bits")]
impl PrimeFieldBits for Scalar {
#[cfg(target_pointer_width = "32")]
type ReprBits = [u32; 8];
#[cfg(target_pointer_width = "64")]
type ReprBits = [u64; 4];
fn to_le_bits(&self) -> ScalarBits {
self.0.as_uint().to_words().into()
}
fn char_le_bits() -> ScalarBits {
MockCurve::ORDER.to_words().into()
}
}
impl AsRef<Scalar> for Scalar {
fn as_ref(&self) -> &Scalar {
self
}
}
impl ConditionallySelectable for Scalar {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(ScalarPrimitive::conditional_select(&a.0, &b.0, choice))
}
}
impl ConstantTimeEq for Scalar {
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&other.0)
}
}
impl DefaultIsZeroes for Scalar {}
impl Add<Scalar> for Scalar {
type Output = Scalar;
fn add(self, other: Scalar) -> Scalar {
self.add(&other)
}
}
impl Add<&Scalar> for Scalar {
type Output = Scalar;
fn add(self, other: &Scalar) -> Scalar {
Self(self.0.add(&other.0))
}
}
impl AddAssign<Scalar> for Scalar {
fn add_assign(&mut self, other: Scalar) {
*self = *self + other;
}
}
impl AddAssign<&Scalar> for Scalar {
fn add_assign(&mut self, other: &Scalar) {
*self = *self + other;
}
}
impl Sub<Scalar> for Scalar {
type Output = Scalar;
fn sub(self, other: Scalar) -> Scalar {
self.sub(&other)
}
}
impl Sub<&Scalar> for Scalar {
type Output = Scalar;
fn sub(self, other: &Scalar) -> Scalar {
Self(self.0.sub(&other.0))
}
}
impl SubAssign<Scalar> for Scalar {
fn sub_assign(&mut self, other: Scalar) {
*self = *self - other;
}
}
impl SubAssign<&Scalar> for Scalar {
fn sub_assign(&mut self, other: &Scalar) {
*self = *self - other;
}
}
impl Mul<Scalar> for Scalar {
type Output = Scalar;
fn mul(self, _other: Scalar) -> Scalar {
unimplemented!();
}
}
impl Mul<&Scalar> for Scalar {
type Output = Scalar;
fn mul(self, _other: &Scalar) -> Scalar {
unimplemented!();
}
}
impl MulAssign<Scalar> for Scalar {
fn mul_assign(&mut self, _rhs: Scalar) {
unimplemented!();
}
}
impl MulAssign<&Scalar> for Scalar {
fn mul_assign(&mut self, _rhs: &Scalar) {
unimplemented!();
}
}
impl Neg for Scalar {
type Output = Scalar;
fn neg(self) -> Scalar {
Self(self.0.neg())
}
}
impl ShrAssign<usize> for Scalar {
fn shr_assign(&mut self, rhs: usize) {
self.0 >>= rhs;
}
}
impl Sum for Scalar {
fn sum<I: Iterator<Item = Self>>(_iter: I) -> Self {
unimplemented!();
}
}
impl<'a> Sum<&'a Scalar> for Scalar {
fn sum<I: Iterator<Item = &'a Scalar>>(_iter: I) -> Self {
unimplemented!();
}
}
impl Product for Scalar {
fn product<I: Iterator<Item = Self>>(_iter: I) -> Self {
unimplemented!();
}
}
impl<'a> Product<&'a Scalar> for Scalar {
fn product<I: Iterator<Item = &'a Scalar>>(_iter: I) -> Self {
unimplemented!();
}
}
impl Invert for Scalar {
type Output = CtOption<Scalar>;
fn invert(&self) -> CtOption<Scalar> {
unimplemented!();
}
}
impl Reduce<U256> for Scalar {
type Bytes = FieldBytes;
fn reduce(w: U256) -> Self {
let (r, underflow) = w.sbb(&MockCurve::ORDER, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
let reduced = U256::conditional_select(&w, &r, !underflow);
Self(ScalarPrimitive::new(reduced).unwrap())
}
fn reduce_bytes(_: &FieldBytes) -> Self {
todo!()
}
}
impl FieldBytesEncoding<MockCurve> for U256 {}
impl From<u64> for Scalar {
fn from(n: u64) -> Scalar {
Self(n.into())
}
}
impl From<ScalarPrimitive> for Scalar {
fn from(scalar: ScalarPrimitive) -> Scalar {
Self(scalar)
}
}
impl From<Scalar> for ScalarPrimitive {
fn from(scalar: Scalar) -> ScalarPrimitive {
scalar.0
}
}
impl From<Scalar> for U256 {
fn from(scalar: Scalar) -> U256 {
scalar.0.to_uint()
}
}
impl TryFrom<U256> for Scalar {
type Error = Error;
fn try_from(w: U256) -> Result<Self> {
Option::from(ScalarPrimitive::new(w)).map(Self).ok_or(Error)
}
}
impl FromUintUnchecked for Scalar {
type Uint = U256;
fn from_uint_unchecked(uint: U256) -> Self {
Self(ScalarPrimitive::from_uint_unchecked(uint))
}
}
impl From<Scalar> for FieldBytes {
fn from(scalar: Scalar) -> Self {
Self::from(&scalar)
}
}
impl From<&Scalar> for FieldBytes {
fn from(scalar: &Scalar) -> Self {
scalar.to_repr()
}
}
impl IsHigh for Scalar {
fn is_high(&self) -> Choice {
self.0.is_high()
}
}
/// Example affine point type
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AffinePoint {
/// Result of fixed-based scalar multiplication.
FixedBaseOutput(Scalar),
/// Identity.
Identity,
/// Base point.
Generator,
/// Point corresponding to a given [`EncodedPoint`].
Other(EncodedPoint),
}
impl AffineCoordinates for AffinePoint {
type FieldRepr = FieldBytes;
fn x(&self) -> FieldBytes {
unimplemented!();
}
fn y_is_odd(&self) -> Choice {
unimplemented!();
}
}
impl ConstantTimeEq for AffinePoint {
fn ct_eq(&self, other: &Self) -> Choice {
match (self, other) {
(Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => {
scalar.ct_eq(other_scalar)
}
(Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(),
(Self::Other(point), Self::Other(other_point)) => u8::from(point == other_point).into(),
_ => 0.into(),
}
}
}
impl ConditionallySelectable for AffinePoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
// Not really constant time, but this is dev code
if choice.into() {
*b
} else {
*a
}
}
}
impl Default for AffinePoint {
fn default() -> Self {
Self::Identity
}
}
impl DefaultIsZeroes for AffinePoint {}
impl FromEncodedPoint<MockCurve> for AffinePoint {
fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption<Self> {
let point = if encoded_point.is_identity() {
Self::Identity
} else {
Self::Other(*encoded_point)
};
CtOption::new(point, Choice::from(1))
}
}
impl ToEncodedPoint<MockCurve> for AffinePoint {
fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
match self {
Self::FixedBaseOutput(scalar) => EncodedPoint::from_affine_coordinates(
&scalar.to_repr(),
&PSEUDO_COORDINATE_FIXED_BASE_MUL.into(),
false,
),
Self::Other(point) => {
if compress == point.is_compressed() {
*point
} else {
unimplemented!();
}
}
_ => unimplemented!(),
}
}
}
impl Mul<NonZeroScalar> for AffinePoint {
type Output = AffinePoint;
fn mul(self, _scalar: NonZeroScalar) -> Self {
unimplemented!();
}
}
/// Example projective point type
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ProjectivePoint {
/// Result of fixed-based scalar multiplication
FixedBaseOutput(Scalar),
/// Is this point the identity point?
Identity,
/// Is this point the generator point?
Generator,
/// Is this point a different point corresponding to a given [`AffinePoint`]
Other(AffinePoint),
}
impl ConstantTimeEq for ProjectivePoint {
fn ct_eq(&self, other: &Self) -> Choice {
match (self, other) {
(Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => {
scalar.ct_eq(other_scalar)
}
(Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(),
(Self::Other(point), Self::Other(other_point)) => point.ct_eq(other_point),
_ => 0.into(),
}
}
}
impl ConditionallySelectable for ProjectivePoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
if choice.into() {
*b
} else {
*a
}
}
}
impl Default for ProjectivePoint {
fn default() -> Self {
Self::Identity
}
}
impl DefaultIsZeroes for ProjectivePoint {}
impl From<AffinePoint> for ProjectivePoint {
fn from(point: AffinePoint) -> ProjectivePoint {
match point {
AffinePoint::FixedBaseOutput(scalar) => ProjectivePoint::FixedBaseOutput(scalar),
AffinePoint::Identity => ProjectivePoint::Identity,
AffinePoint::Generator => ProjectivePoint::Generator,
other => ProjectivePoint::Other(other),
}
}
}
impl From<ProjectivePoint> for AffinePoint {
fn from(point: ProjectivePoint) -> AffinePoint {
group::Curve::to_affine(&point)
}
}
impl FromEncodedPoint<MockCurve> for ProjectivePoint {
fn from_encoded_point(_point: &EncodedPoint) -> CtOption<Self> {
unimplemented!();
}
}
impl ToEncodedPoint<MockCurve> for ProjectivePoint {
fn to_encoded_point(&self, _compress: bool) -> EncodedPoint {
unimplemented!();
}
}
impl group::Group for ProjectivePoint {
type Scalar = Scalar;
fn random(_rng: impl RngCore) -> Self {
unimplemented!();
}
fn identity() -> Self {
Self::Identity
}
fn generator() -> Self {
Self::Generator
}
fn is_identity(&self) -> Choice {
Choice::from(u8::from(self == &Self::Identity))
}
#[must_use]
fn double(&self) -> Self {
unimplemented!();
}
}
impl group::GroupEncoding for AffinePoint {
type Repr = CompressedPoint<MockCurve>;
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
EncodedPoint::from_bytes(bytes)
.map(|point| CtOption::new(point, Choice::from(1)))
.unwrap_or_else(|_| {
let is_identity = bytes.ct_eq(&Self::Repr::default());
CtOption::new(EncodedPoint::identity(), is_identity)
})
.and_then(|point| Self::from_encoded_point(&point))
}
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
Self::from_bytes(bytes)
}
fn to_bytes(&self) -> Self::Repr {
let encoded = self.to_encoded_point(true);
let mut result = CompressedPoint::<MockCurve>::default();
result[..encoded.len()].copy_from_slice(encoded.as_bytes());
result
}
}
impl group::GroupEncoding for ProjectivePoint {
type Repr = CompressedPoint<MockCurve>;
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
<AffinePoint as group::GroupEncoding>::from_bytes(bytes).map(Into::into)
}
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
Self::from_bytes(bytes)
}
fn to_bytes(&self) -> Self::Repr {
group::Curve::to_affine(self).to_bytes()
}
}
impl group::Curve for ProjectivePoint {
type AffineRepr = AffinePoint;
fn to_affine(&self) -> AffinePoint {
match self {
Self::FixedBaseOutput(scalar) => AffinePoint::FixedBaseOutput(*scalar),
Self::Other(affine) => *affine,
_ => unimplemented!(),
}
}
}
impl LinearCombination for ProjectivePoint {}
impl Add<ProjectivePoint> for ProjectivePoint {
type Output = ProjectivePoint;
fn add(self, _other: ProjectivePoint) -> ProjectivePoint {
unimplemented!();
}
}
impl Add<&ProjectivePoint> for ProjectivePoint {
type Output = ProjectivePoint;
fn add(self, _other: &ProjectivePoint) -> ProjectivePoint {
unimplemented!();
}
}
impl AddAssign<ProjectivePoint> for ProjectivePoint {
fn add_assign(&mut self, _rhs: ProjectivePoint) {
unimplemented!();
}
}
impl AddAssign<&ProjectivePoint> for ProjectivePoint {
fn add_assign(&mut self, _rhs: &ProjectivePoint) {
unimplemented!();
}
}
impl Sub<ProjectivePoint> for ProjectivePoint {
type Output = ProjectivePoint;
fn sub(self, _other: ProjectivePoint) -> ProjectivePoint {
unimplemented!();
}
}
impl Sub<&ProjectivePoint> for ProjectivePoint {
type Output = ProjectivePoint;
fn sub(self, _other: &ProjectivePoint) -> ProjectivePoint {
unimplemented!();
}
}
impl SubAssign<ProjectivePoint> for ProjectivePoint {
fn sub_assign(&mut self, _rhs: ProjectivePoint) {
unimplemented!();
}
}
impl SubAssign<&ProjectivePoint> for ProjectivePoint {
fn sub_assign(&mut self, _rhs: &ProjectivePoint) {
unimplemented!();
}
}
impl Add<AffinePoint> for ProjectivePoint {
type Output = ProjectivePoint;
fn add(self, _other: AffinePoint) -> ProjectivePoint {
unimplemented!();
}
}
impl Add<&AffinePoint> for ProjectivePoint {
type Output = ProjectivePoint;
fn add(self, _other: &AffinePoint) -> ProjectivePoint {
unimplemented!();
}
}
impl AddAssign<AffinePoint> for ProjectivePoint {
fn add_assign(&mut self, _rhs: AffinePoint) {
unimplemented!();
}
}
impl AddAssign<&AffinePoint> for ProjectivePoint {
fn add_assign(&mut self, _rhs: &AffinePoint) {
unimplemented!();
}
}
impl Sum for ProjectivePoint {
fn sum<I: Iterator<Item = Self>>(_iter: I) -> Self {
unimplemented!();
}
}
impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint {
fn sum<I: Iterator<Item = &'a ProjectivePoint>>(_iter: I) -> Self {
unimplemented!();
}
}
impl Sub<AffinePoint> for ProjectivePoint {
type Output = ProjectivePoint;
fn sub(self, _other: AffinePoint) -> ProjectivePoint {
unimplemented!();
}
}
impl Sub<&AffinePoint> for ProjectivePoint {
type Output = ProjectivePoint;
fn sub(self, _other: &AffinePoint) -> ProjectivePoint {
unimplemented!();
}
}
impl SubAssign<AffinePoint> for ProjectivePoint {
fn sub_assign(&mut self, _rhs: AffinePoint) {
unimplemented!();
}
}
impl SubAssign<&AffinePoint> for ProjectivePoint {
fn sub_assign(&mut self, _rhs: &AffinePoint) {
unimplemented!();
}
}
impl Mul<Scalar> for ProjectivePoint {
type Output = ProjectivePoint;
fn mul(self, scalar: Scalar) -> ProjectivePoint {
match self {
Self::Generator => Self::FixedBaseOutput(scalar),
_ => unimplemented!(),
}
}
}
impl Mul<&Scalar> for ProjectivePoint {
type Output = ProjectivePoint;
fn mul(self, scalar: &Scalar) -> ProjectivePoint {
self * *scalar
}
}
impl MulAssign<Scalar> for ProjectivePoint {
fn mul_assign(&mut self, _rhs: Scalar) {
unimplemented!();
}
}
impl MulAssign<&Scalar> for ProjectivePoint {
fn mul_assign(&mut self, _rhs: &Scalar) {
unimplemented!();
}
}
impl MulByGenerator for ProjectivePoint {}
impl Neg for ProjectivePoint {
type Output = ProjectivePoint;
fn neg(self) -> ProjectivePoint {
unimplemented!();
}
}
#[cfg(test)]
mod tests {
use super::Scalar;
use ff::PrimeField;
use hex_literal::hex;
#[test]
fn round_trip() {
let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
let scalar = Scalar::from_repr(bytes.into()).unwrap();
assert_eq!(&bytes, scalar.to_repr().as_slice());
}
}

236
vendor/elliptic-curve/src/ecdh.rs vendored Normal file
View File

@@ -0,0 +1,236 @@
//! Elliptic Curve Diffie-Hellman Support.
//!
//! This module contains a generic ECDH implementation which is usable with
//! any elliptic curve which implements the [`CurveArithmetic`] trait (presently
//! the `k256` and `p256` crates)
//!
//! # ECDH Ephemeral (ECDHE) Usage
//!
//! Ephemeral Diffie-Hellman provides a one-time key exchange between two peers
//! using a randomly generated set of keys for each exchange.
//!
//! In practice ECDHE is used as part of an [Authenticated Key Exchange (AKE)][AKE]
//! protocol (e.g. [SIGMA]), where an existing cryptographic trust relationship
//! can be used to determine the authenticity of the ephemeral keys, such as
//! a digital signature. Without such an additional step, ECDHE is insecure!
//! (see security warning below)
//!
//! See the documentation for the [`EphemeralSecret`] type for more information
//! on performing ECDH ephemeral key exchanges.
//!
//! # Static ECDH Usage
//!
//! Static ECDH key exchanges are supported via the low-level
//! [`diffie_hellman`] function.
//!
//! [AKE]: https://en.wikipedia.org/wiki/Authenticated_Key_Exchange
//! [SIGMA]: https://webee.technion.ac.il/~hugo/sigma-pdf.pdf
use crate::{
point::AffineCoordinates, AffinePoint, Curve, CurveArithmetic, FieldBytes, NonZeroScalar,
ProjectivePoint, PublicKey,
};
use core::borrow::Borrow;
use digest::{crypto_common::BlockSizeUser, Digest};
use group::Curve as _;
use hkdf::{hmac::SimpleHmac, Hkdf};
use rand_core::CryptoRngCore;
use zeroize::{Zeroize, ZeroizeOnDrop};
/// Low-level Elliptic Curve Diffie-Hellman (ECDH) function.
///
/// Whenever possible, we recommend using the high-level ECDH ephemeral API
/// provided by [`EphemeralSecret`].
///
/// However, if you are implementing a protocol which requires a static scalar
/// value as part of an ECDH exchange, this API can be used to compute a
/// [`SharedSecret`] from that value.
///
/// Note that this API operates on the low-level [`NonZeroScalar`] and
/// [`AffinePoint`] types. If you are attempting to use the higher-level
/// [`SecretKey`][`crate::SecretKey`] and [`PublicKey`] types, you will
/// need to use the following conversions:
///
/// ```ignore
/// let shared_secret = elliptic_curve::ecdh::diffie_hellman(
/// secret_key.to_nonzero_scalar(),
/// public_key.as_affine()
/// );
/// ```
pub fn diffie_hellman<C>(
secret_key: impl Borrow<NonZeroScalar<C>>,
public_key: impl Borrow<AffinePoint<C>>,
) -> SharedSecret<C>
where
C: CurveArithmetic,
{
let public_point = ProjectivePoint::<C>::from(*public_key.borrow());
let secret_point = (public_point * secret_key.borrow().as_ref()).to_affine();
SharedSecret::new(secret_point)
}
/// Ephemeral Diffie-Hellman Secret.
///
/// These are ephemeral "secret key" values which are deliberately designed
/// to avoid being persisted.
///
/// To perform an ephemeral Diffie-Hellman exchange, do the following:
///
/// - Have each participant generate an [`EphemeralSecret`] value
/// - Compute the [`PublicKey`] for that value
/// - Have each peer provide their [`PublicKey`] to their counterpart
/// - Use [`EphemeralSecret`] and the other participant's [`PublicKey`]
/// to compute a [`SharedSecret`] value.
///
/// # ⚠️ SECURITY WARNING ⚠️
///
/// Ephemeral Diffie-Hellman exchanges are unauthenticated and without a
/// further authentication step are trivially vulnerable to man-in-the-middle
/// attacks!
///
/// These exchanges should be performed in the context of a protocol which
/// takes further steps to authenticate the peers in a key exchange.
pub struct EphemeralSecret<C>
where
C: CurveArithmetic,
{
scalar: NonZeroScalar<C>,
}
impl<C> EphemeralSecret<C>
where
C: CurveArithmetic,
{
/// Generate a cryptographically random [`EphemeralSecret`].
pub fn random(rng: &mut impl CryptoRngCore) -> Self {
Self {
scalar: NonZeroScalar::random(rng),
}
}
/// Get the public key associated with this ephemeral secret.
///
/// The `compress` flag enables point compression.
pub fn public_key(&self) -> PublicKey<C> {
PublicKey::from_secret_scalar(&self.scalar)
}
/// Compute a Diffie-Hellman shared secret from an ephemeral secret and the
/// public key of the other participant in the exchange.
pub fn diffie_hellman(&self, public_key: &PublicKey<C>) -> SharedSecret<C> {
diffie_hellman(self.scalar, public_key.as_affine())
}
}
impl<C> From<&EphemeralSecret<C>> for PublicKey<C>
where
C: CurveArithmetic,
{
fn from(ephemeral_secret: &EphemeralSecret<C>) -> Self {
ephemeral_secret.public_key()
}
}
impl<C> Zeroize for EphemeralSecret<C>
where
C: CurveArithmetic,
{
fn zeroize(&mut self) {
self.scalar.zeroize()
}
}
impl<C> ZeroizeOnDrop for EphemeralSecret<C> where C: CurveArithmetic {}
impl<C> Drop for EphemeralSecret<C>
where
C: CurveArithmetic,
{
fn drop(&mut self) {
self.zeroize();
}
}
/// Shared secret value computed via ECDH key agreement.
pub struct SharedSecret<C: Curve> {
/// Computed secret value
secret_bytes: FieldBytes<C>,
}
impl<C: Curve> SharedSecret<C> {
/// Create a new [`SharedSecret`] from an [`AffinePoint`] for this curve.
#[inline]
fn new(point: AffinePoint<C>) -> Self
where
C: CurveArithmetic,
{
Self {
secret_bytes: point.x(),
}
}
/// Use [HKDF] (HMAC-based Extract-and-Expand Key Derivation Function) to
/// extract entropy from this shared secret.
///
/// This method can be used to transform the shared secret into uniformly
/// random values which are suitable as key material.
///
/// The `D` type parameter is a cryptographic digest function.
/// `sha2::Sha256` is a common choice for use with HKDF.
///
/// The `salt` parameter can be used to supply additional randomness.
/// Some examples include:
///
/// - randomly generated (but authenticated) string
/// - fixed application-specific value
/// - previous shared secret used for rekeying (as in TLS 1.3 and Noise)
///
/// After initializing HKDF, use [`Hkdf::expand`] to obtain output key
/// material.
///
/// [HKDF]: https://en.wikipedia.org/wiki/HKDF
pub fn extract<D>(&self, salt: Option<&[u8]>) -> Hkdf<D, SimpleHmac<D>>
where
D: BlockSizeUser + Clone + Digest,
{
Hkdf::new(salt, &self.secret_bytes)
}
/// This value contains the raw serialized x-coordinate of the elliptic curve
/// point computed from a Diffie-Hellman exchange, serialized as bytes.
///
/// When in doubt, use [`SharedSecret::extract`] instead.
///
/// # ⚠️ WARNING: NOT UNIFORMLY RANDOM! ⚠️
///
/// This value is not uniformly random and should not be used directly
/// as a cryptographic key for anything which requires that property
/// (e.g. symmetric ciphers).
///
/// Instead, the resulting value should be used as input to a Key Derivation
/// Function (KDF) or cryptographic hash function to produce a symmetric key.
/// The [`SharedSecret::extract`] function will do this for you.
pub fn raw_secret_bytes(&self) -> &FieldBytes<C> {
&self.secret_bytes
}
}
impl<C: Curve> From<FieldBytes<C>> for SharedSecret<C> {
/// NOTE: this impl is intended to be used by curve implementations to
/// instantiate a [`SharedSecret`] value from their respective
/// [`AffinePoint`] type.
///
/// Curve implementations should provide the field element representing
/// the affine x-coordinate as `secret_bytes`.
fn from(secret_bytes: FieldBytes<C>) -> Self {
Self { secret_bytes }
}
}
impl<C: Curve> ZeroizeOnDrop for SharedSecret<C> {}
impl<C: Curve> Drop for SharedSecret<C> {
fn drop(&mut self) {
self.secret_bytes.zeroize()
}
}

42
vendor/elliptic-curve/src/error.rs vendored Normal file
View File

@@ -0,0 +1,42 @@
//! Error type.
use core::fmt::{self, Display};
#[cfg(feature = "pkcs8")]
use crate::pkcs8;
/// Result type with the `elliptic-curve` crate's [`Error`] type.
pub type Result<T> = core::result::Result<T, Error>;
/// Elliptic curve errors.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Error;
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("crypto error")
}
}
impl From<base16ct::Error> for Error {
fn from(_: base16ct::Error) -> Error {
Error
}
}
#[cfg(feature = "pkcs8")]
impl From<pkcs8::Error> for Error {
fn from(_: pkcs8::Error) -> Error {
Error
}
}
#[cfg(feature = "sec1")]
impl From<sec1::Error> for Error {
fn from(_: sec1::Error) -> Error {
Error
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}

51
vendor/elliptic-curve/src/field.rs vendored Normal file
View File

@@ -0,0 +1,51 @@
//! Field elements.
use crate::{
bigint::{ArrayEncoding, ByteArray, Integer},
Curve,
};
use generic_array::{typenum::Unsigned, GenericArray};
/// Size of serialized field elements of this elliptic curve.
pub type FieldBytesSize<C> = <C as Curve>::FieldBytesSize;
/// Byte representation of a base/scalar field element of a given curve.
pub type FieldBytes<C> = GenericArray<u8, FieldBytesSize<C>>;
/// Trait for decoding/encoding `Curve::Uint` from/to [`FieldBytes`] using
/// curve-specific rules.
///
/// Namely a curve's modulus may be smaller than the big integer type used to
/// internally represent field elements (since the latter are multiples of the
/// limb size), such as in the case of curves like NIST P-224 and P-521, and so
/// it may need to be padded/truncated to the right length.
///
/// Additionally, different curves have different endianness conventions, also
/// captured here.
pub trait FieldBytesEncoding<C>: ArrayEncoding + Integer
where
C: Curve,
{
/// Decode unsigned integer from serialized field element.
///
/// The default implementation assumes a big endian encoding.
fn decode_field_bytes(field_bytes: &FieldBytes<C>) -> Self {
debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE);
let mut byte_array = ByteArray::<Self>::default();
let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len());
byte_array[offset..].copy_from_slice(field_bytes);
Self::from_be_byte_array(byte_array)
}
/// Encode unsigned integer into serialized field element.
///
/// The default implementation assumes a big endian encoding.
fn encode_field_bytes(&self) -> FieldBytes<C> {
let mut field_bytes = FieldBytes::<C>::default();
debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE);
let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len());
field_bytes.copy_from_slice(&self.to_be_byte_array()[offset..]);
field_bytes
}
}

15
vendor/elliptic-curve/src/hash2curve.rs vendored Normal file
View File

@@ -0,0 +1,15 @@
//! Traits for hashing byte sequences to curve points.
//!
//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve>
mod group_digest;
mod hash2field;
mod isogeny;
mod map2curve;
mod osswu;
pub use group_digest::*;
pub use hash2field::*;
pub use isogeny::*;
pub use map2curve::*;
pub use osswu::*;

View File

@@ -0,0 +1,123 @@
//! Traits for handling hash to curve.
use super::{hash_to_field, ExpandMsg, FromOkm, MapToCurve};
use crate::{CurveArithmetic, ProjectivePoint, Result};
use group::cofactor::CofactorGroup;
/// Adds hashing arbitrary byte sequences to a valid group element
pub trait GroupDigest: CurveArithmetic
where
ProjectivePoint<Self>: CofactorGroup,
{
/// The field element representation for a group value with multiple elements
type FieldElement: FromOkm + MapToCurve<Output = ProjectivePoint<Self>> + Default + Copy;
/// Computes the hash to curve routine.
///
/// From <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html>:
///
/// > Uniform encoding from byte strings to points in G.
/// > That is, the distribution of its output is statistically close
/// > to uniform in G.
/// > This function is suitable for most applications requiring a random
/// > oracle returning points in G assuming a cryptographically secure
/// > hash function is used.
///
/// # Examples
///
/// ## Using a fixed size hash function
///
/// ```ignore
/// let pt = ProjectivePoint::hash_from_bytes::<ExpandMsgXmd<sha2::Sha256>>(b"test data", b"CURVE_XMD:SHA-256_SSWU_RO_");
/// ```
///
/// ## Using an extendable output function
///
/// ```ignore
/// let pt = ProjectivePoint::hash_from_bytes::<ExpandMsgXof<sha3::Shake256>>(b"test data", b"CURVE_XOF:SHAKE-256_SSWU_RO_");
/// ```
///
/// # Errors
/// See implementors of [`ExpandMsg`] for errors:
/// - [`ExpandMsgXmd`]
/// - [`ExpandMsgXof`]
///
/// `len_in_bytes = <Self::FieldElement as FromOkm>::Length * 2`
///
/// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd
/// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof
fn hash_from_bytes<'a, X: ExpandMsg<'a>>(
msgs: &[&[u8]],
dsts: &'a [&'a [u8]],
) -> Result<ProjectivePoint<Self>> {
let mut u = [Self::FieldElement::default(), Self::FieldElement::default()];
hash_to_field::<X, _>(msgs, dsts, &mut u)?;
let q0 = u[0].map_to_curve();
let q1 = u[1].map_to_curve();
// Ideally we could add and then clear cofactor once
// thus saving a call but the field elements may not
// add properly due to the underlying implementation
// which could result in an incorrect subgroup.
// This is caused curve coefficients being different than
// what is usually implemented.
// FieldElement expects the `a` and `b` to be the original values
// isogenies are different with curves like k256 and bls12-381.
// This problem doesn't manifest for curves with no isogeny like p256.
// For k256 and p256 clear_cofactor doesn't do anything anyway so it will be a no-op.
Ok(q0.clear_cofactor().into() + q1.clear_cofactor())
}
/// Computes the encode to curve routine.
///
/// From <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html>:
///
/// > Nonuniform encoding from byte strings to
/// > points in G. That is, the distribution of its output is not
/// > uniformly random in G: the set of possible outputs of
/// > encode_to_curve is only a fraction of the points in G, and some
/// > points in this set are more likely to be output than others.
///
/// # Errors
/// See implementors of [`ExpandMsg`] for errors:
/// - [`ExpandMsgXmd`]
/// - [`ExpandMsgXof`]
///
/// `len_in_bytes = <Self::FieldElement as FromOkm>::Length`
///
/// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd
/// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof
fn encode_from_bytes<'a, X: ExpandMsg<'a>>(
msgs: &[&[u8]],
dsts: &'a [&'a [u8]],
) -> Result<ProjectivePoint<Self>> {
let mut u = [Self::FieldElement::default()];
hash_to_field::<X, _>(msgs, dsts, &mut u)?;
let q0 = u[0].map_to_curve();
Ok(q0.clear_cofactor().into())
}
/// Computes the hash to field routine according to
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5>
/// and returns a scalar.
///
/// # Errors
/// See implementors of [`ExpandMsg`] for errors:
/// - [`ExpandMsgXmd`]
/// - [`ExpandMsgXof`]
///
/// `len_in_bytes = <Self::Scalar as FromOkm>::Length`
///
/// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd
/// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof
fn hash_to_scalar<'a, X: ExpandMsg<'a>>(
msgs: &[&[u8]],
dsts: &'a [&'a [u8]],
) -> Result<Self::Scalar>
where
Self::Scalar: FromOkm,
{
let mut u = [Self::Scalar::default()];
hash_to_field::<X, _>(msgs, dsts, &mut u)?;
Ok(u[0])
}
}

View File

@@ -0,0 +1,48 @@
//! Traits for hashing to field elements.
//!
//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve>
mod expand_msg;
pub use expand_msg::{xmd::*, xof::*, *};
use crate::{Error, Result};
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
/// The trait for helping to convert to a field element.
pub trait FromOkm {
/// The number of bytes needed to convert to a field element.
type Length: ArrayLength<u8>;
/// Convert a byte sequence into a field element.
fn from_okm(data: &GenericArray<u8, Self::Length>) -> Self;
}
/// Convert an arbitrary byte sequence into a field element.
///
/// <https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3>
///
/// # Errors
/// See implementors of [`ExpandMsg`] for errors:
/// - [`ExpandMsgXmd`]
/// - [`ExpandMsgXof`]
///
/// `len_in_bytes = T::Length * out.len()`
///
/// [`ExpandMsgXmd`]: crate::hash2field::ExpandMsgXmd
/// [`ExpandMsgXof`]: crate::hash2field::ExpandMsgXof
#[doc(hidden)]
pub fn hash_to_field<'a, E, T>(data: &[&[u8]], domain: &'a [&'a [u8]], out: &mut [T]) -> Result<()>
where
E: ExpandMsg<'a>,
T: FromOkm + Default,
{
let len_in_bytes = T::Length::to_usize().checked_mul(out.len()).ok_or(Error)?;
let mut tmp = GenericArray::<u8, <T as FromOkm>::Length>::default();
let mut expander = E::expand_message(data, domain, len_in_bytes)?;
for o in out.iter_mut() {
expander.fill_bytes(&mut tmp);
*o = T::from_okm(&tmp);
}
Ok(())
}

View File

@@ -0,0 +1,145 @@
//! `expand_message` interface `for hash_to_field`.
pub(super) mod xmd;
pub(super) mod xof;
use crate::{Error, Result};
use digest::{Digest, ExtendableOutput, Update, XofReader};
use generic_array::typenum::{IsLess, U256};
use generic_array::{ArrayLength, GenericArray};
/// Salt when the DST is too long
const OVERSIZE_DST_SALT: &[u8] = b"H2C-OVERSIZE-DST-";
/// Maximum domain separation tag length
const MAX_DST_LEN: usize = 255;
/// Trait for types implementing expand_message interface for `hash_to_field`.
///
/// # Errors
/// See implementors of [`ExpandMsg`] for errors.
pub trait ExpandMsg<'a> {
/// Type holding data for the [`Expander`].
type Expander: Expander + Sized;
/// Expands `msg` to the required number of bytes.
///
/// Returns an expander that can be used to call `read` until enough
/// bytes have been consumed
fn expand_message(
msgs: &[&[u8]],
dsts: &'a [&'a [u8]],
len_in_bytes: usize,
) -> Result<Self::Expander>;
}
/// Expander that, call `read` until enough bytes have been consumed.
pub trait Expander {
/// Fill the array with the expanded bytes
fn fill_bytes(&mut self, okm: &mut [u8]);
}
/// The domain separation tag
///
/// Implements [section 5.4.3 of `draft-irtf-cfrg-hash-to-curve-13`][dst].
///
/// [dst]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-13#section-5.4.3
pub(crate) enum Domain<'a, L>
where
L: ArrayLength<u8> + IsLess<U256>,
{
/// > 255
Hashed(GenericArray<u8, L>),
/// <= 255
Array(&'a [&'a [u8]]),
}
impl<'a, L> Domain<'a, L>
where
L: ArrayLength<u8> + IsLess<U256>,
{
pub fn xof<X>(dsts: &'a [&'a [u8]]) -> Result<Self>
where
X: Default + ExtendableOutput + Update,
{
if dsts.is_empty() {
Err(Error)
} else if dsts.iter().map(|dst| dst.len()).sum::<usize>() > MAX_DST_LEN {
let mut data = GenericArray::<u8, L>::default();
let mut hash = X::default();
hash.update(OVERSIZE_DST_SALT);
for dst in dsts {
hash.update(dst);
}
hash.finalize_xof().read(&mut data);
Ok(Self::Hashed(data))
} else {
Ok(Self::Array(dsts))
}
}
pub fn xmd<X>(dsts: &'a [&'a [u8]]) -> Result<Self>
where
X: Digest<OutputSize = L>,
{
if dsts.is_empty() {
Err(Error)
} else if dsts.iter().map(|dst| dst.len()).sum::<usize>() > MAX_DST_LEN {
Ok(Self::Hashed({
let mut hash = X::new();
hash.update(OVERSIZE_DST_SALT);
for dst in dsts {
hash.update(dst);
}
hash.finalize()
}))
} else {
Ok(Self::Array(dsts))
}
}
pub fn update_hash<HashT: Update>(&self, hash: &mut HashT) {
match self {
Self::Hashed(d) => hash.update(d),
Self::Array(d) => {
for d in d.iter() {
hash.update(d)
}
}
}
}
pub fn len(&self) -> u8 {
match self {
// Can't overflow because it's enforced on a type level.
Self::Hashed(_) => L::to_u8(),
// Can't overflow because it's checked on creation.
Self::Array(d) => {
u8::try_from(d.iter().map(|d| d.len()).sum::<usize>()).expect("length overflow")
}
}
}
#[cfg(test)]
pub fn assert(&self, bytes: &[u8]) {
let data = match self {
Domain::Hashed(d) => d.to_vec(),
Domain::Array(d) => d.iter().copied().flatten().copied().collect(),
};
assert_eq!(data, bytes);
}
#[cfg(test)]
pub fn assert_dst(&self, bytes: &[u8]) {
let data = match self {
Domain::Hashed(d) => d.to_vec(),
Domain::Array(d) => d.iter().copied().flatten().copied().collect(),
};
assert_eq!(data, &bytes[..bytes.len() - 1]);
assert_eq!(self.len(), bytes[bytes.len() - 1]);
}
}

View File

@@ -0,0 +1,451 @@
//! `expand_message_xmd` based on a hash function.
use core::marker::PhantomData;
use super::{Domain, ExpandMsg, Expander};
use crate::{Error, Result};
use digest::{
core_api::BlockSizeUser,
generic_array::{
typenum::{IsLess, IsLessOrEqual, Unsigned, U256},
GenericArray,
},
FixedOutput, HashMarker,
};
/// Placeholder type for implementing `expand_message_xmd` based on a hash function
///
/// # Errors
/// - `dst.is_empty()`
/// - `len_in_bytes == 0`
/// - `len_in_bytes > u16::MAX`
/// - `len_in_bytes > 255 * HashT::OutputSize`
pub struct ExpandMsgXmd<HashT>(PhantomData<HashT>)
where
HashT: BlockSizeUser + Default + FixedOutput + HashMarker,
HashT::OutputSize: IsLess<U256>,
HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>;
/// ExpandMsgXmd implements expand_message_xmd for the ExpandMsg trait
impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXmd<HashT>
where
HashT: BlockSizeUser + Default + FixedOutput + HashMarker,
// If `len_in_bytes` is bigger then 256, length of the `DST` will depend on
// the output size of the hash, which is still not allowed to be bigger then 256:
// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5.4.1-6
HashT::OutputSize: IsLess<U256>,
// Constraint set by `expand_message_xmd`:
// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5.4.1-4
HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>,
{
type Expander = ExpanderXmd<'a, HashT>;
fn expand_message(
msgs: &[&[u8]],
dsts: &'a [&'a [u8]],
len_in_bytes: usize,
) -> Result<Self::Expander> {
if len_in_bytes == 0 {
return Err(Error);
}
let len_in_bytes_u16 = u16::try_from(len_in_bytes).map_err(|_| Error)?;
let b_in_bytes = HashT::OutputSize::to_usize();
let ell = u8::try_from((len_in_bytes + b_in_bytes - 1) / b_in_bytes).map_err(|_| Error)?;
let domain = Domain::xmd::<HashT>(dsts)?;
let mut b_0 = HashT::default();
b_0.update(&GenericArray::<u8, HashT::BlockSize>::default());
for msg in msgs {
b_0.update(msg);
}
b_0.update(&len_in_bytes_u16.to_be_bytes());
b_0.update(&[0]);
domain.update_hash(&mut b_0);
b_0.update(&[domain.len()]);
let b_0 = b_0.finalize_fixed();
let mut b_vals = HashT::default();
b_vals.update(&b_0[..]);
b_vals.update(&[1u8]);
domain.update_hash(&mut b_vals);
b_vals.update(&[domain.len()]);
let b_vals = b_vals.finalize_fixed();
Ok(ExpanderXmd {
b_0,
b_vals,
domain,
index: 1,
offset: 0,
ell,
})
}
}
/// [`Expander`] type for [`ExpandMsgXmd`].
pub struct ExpanderXmd<'a, HashT>
where
HashT: BlockSizeUser + Default + FixedOutput + HashMarker,
HashT::OutputSize: IsLess<U256>,
HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>,
{
b_0: GenericArray<u8, HashT::OutputSize>,
b_vals: GenericArray<u8, HashT::OutputSize>,
domain: Domain<'a, HashT::OutputSize>,
index: u8,
offset: usize,
ell: u8,
}
impl<'a, HashT> ExpanderXmd<'a, HashT>
where
HashT: BlockSizeUser + Default + FixedOutput + HashMarker,
HashT::OutputSize: IsLess<U256>,
HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>,
{
fn next(&mut self) -> bool {
if self.index < self.ell {
self.index += 1;
self.offset = 0;
// b_0 XOR b_(idx - 1)
let mut tmp = GenericArray::<u8, HashT::OutputSize>::default();
self.b_0
.iter()
.zip(&self.b_vals[..])
.enumerate()
.for_each(|(j, (b0val, bi1val))| tmp[j] = b0val ^ bi1val);
let mut b_vals = HashT::default();
b_vals.update(&tmp);
b_vals.update(&[self.index]);
self.domain.update_hash(&mut b_vals);
b_vals.update(&[self.domain.len()]);
self.b_vals = b_vals.finalize_fixed();
true
} else {
false
}
}
}
impl<'a, HashT> Expander for ExpanderXmd<'a, HashT>
where
HashT: BlockSizeUser + Default + FixedOutput + HashMarker,
HashT::OutputSize: IsLess<U256>,
HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>,
{
fn fill_bytes(&mut self, okm: &mut [u8]) {
for b in okm {
if self.offset == self.b_vals.len() && !self.next() {
return;
}
*b = self.b_vals[self.offset];
self.offset += 1;
}
}
}
#[cfg(test)]
mod test {
use super::*;
use core::mem;
use generic_array::{
typenum::{U128, U32},
ArrayLength,
};
use hex_literal::hex;
use sha2::Sha256;
fn assert_message<HashT>(
msg: &[u8],
domain: &Domain<'_, HashT::OutputSize>,
len_in_bytes: u16,
bytes: &[u8],
) where
HashT: BlockSizeUser + Default + FixedOutput + HashMarker,
HashT::OutputSize: IsLess<U256>,
{
let block = HashT::BlockSize::to_usize();
assert_eq!(
GenericArray::<u8, HashT::BlockSize>::default().as_slice(),
&bytes[..block]
);
let msg_len = block + msg.len();
assert_eq!(msg, &bytes[block..msg_len]);
let l = msg_len + mem::size_of::<u16>();
assert_eq!(len_in_bytes.to_be_bytes(), &bytes[msg_len..l]);
let pad = l + mem::size_of::<u8>();
assert_eq!([0], &bytes[l..pad]);
let dst = pad + usize::from(domain.len());
domain.assert(&bytes[pad..dst]);
let dst_len = dst + mem::size_of::<u8>();
assert_eq!([domain.len()], &bytes[dst..dst_len]);
assert_eq!(dst_len, bytes.len());
}
struct TestVector {
msg: &'static [u8],
msg_prime: &'static [u8],
uniform_bytes: &'static [u8],
}
impl TestVector {
#[allow(clippy::panic_in_result_fn)]
fn assert<HashT, L: ArrayLength<u8>>(
&self,
dst: &'static [u8],
domain: &Domain<'_, HashT::OutputSize>,
) -> Result<()>
where
HashT: BlockSizeUser + Default + FixedOutput + HashMarker,
HashT::OutputSize: IsLess<U256> + IsLessOrEqual<HashT::BlockSize>,
{
assert_message::<HashT>(self.msg, domain, L::to_u16(), self.msg_prime);
let dst = [dst];
let mut expander =
ExpandMsgXmd::<HashT>::expand_message(&[self.msg], &dst, L::to_usize())?;
let mut uniform_bytes = GenericArray::<u8, L>::default();
expander.fill_bytes(&mut uniform_bytes);
assert_eq!(uniform_bytes.as_slice(), self.uniform_bytes);
Ok(())
}
}
#[test]
fn expand_message_xmd_sha_256() -> Result<()> {
const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA256-128";
const DST_PRIME: &[u8] =
&hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826");
let dst_prime = Domain::xmd::<Sha256>(&[DST])?;
dst_prime.assert_dst(DST_PRIME);
const TEST_VECTORS_32: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("d8ccab23b5985ccea865c6c97b6e5b8350e794e603b4b97902f53a8a0d605615"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("eff31487c770a893cfb36f912fbfcbff40d5661771ca4b2cb4eafe524333f5c1"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("b23a1d2b4d97b2ef7785562a7e8bac7eed54ed6e97e29aa51bfe3f12ddad1ff9"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("4623227bcc01293b8c130bf771da8c298dede7383243dc0993d2d94823958c4c"),
},
];
for test_vector in TEST_VECTORS_32 {
test_vector.assert::<Sha256, U32>(DST, &dst_prime)?;
}
const TEST_VECTORS_128: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("af84c27ccfd45d41914fdff5df25293e221afc53d8ad2ac06d5e3e29485dadbee0d121587713a3e0dd4d5e69e93eb7cd4f5df4cd103e188cf60cb02edc3edf18eda8576c412b18ffb658e3dd6ec849469b979d444cf7b26911a08e63cf31f9dcc541708d3491184472c2c29bb749d4286b004ceb5ee6b9a7fa5b646c993f0ced"),
}, TestVector {
msg: b"abc",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("abba86a6129e366fc877aab32fc4ffc70120d8996c88aee2fe4b32d6c7b6437a647e6c3163d40b76a73cf6a5674ef1d890f95b664ee0afa5359a5c4e07985635bbecbac65d747d3d2da7ec2b8221b17b0ca9dc8a1ac1c07ea6a1e60583e2cb00058e77b7b72a298425cd1b941ad4ec65e8afc50303a22c0f99b0509b4c895f40"),
}, TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("ef904a29bffc4cf9ee82832451c946ac3c8f8058ae97d8d629831a74c6572bd9ebd0df635cd1f208e2038e760c4994984ce73f0d55ea9f22af83ba4734569d4bc95e18350f740c07eef653cbb9f87910d833751825f0ebefa1abe5420bb52be14cf489b37fe1a72f7de2d10be453b2c9d9eb20c7e3f6edc5a60629178d9478df"),
}, TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("80be107d0884f0d881bb460322f0443d38bd222db8bd0b0a5312a6fedb49c1bbd88fd75d8b9a09486c60123dfa1d73c1cc3169761b17476d3c6b7cbbd727acd0e2c942f4dd96ae3da5de368d26b32286e32de7e5a8cb2949f866a0b80c58116b29fa7fabb3ea7d520ee603e0c25bcaf0b9a5e92ec6a1fe4e0391d1cdbce8c68a"),
}, TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"),
uniform_bytes: &hex!("546aff5444b5b79aa6148bd81728704c32decb73a3ba76e9e75885cad9def1d06d6792f8a7d12794e90efed817d96920d728896a4510864370c207f99bd4a608ea121700ef01ed879745ee3e4ceef777eda6d9e5e38b90c86ea6fb0b36504ba4a45d22e86f6db5dd43d98a294bebb9125d5b794e9d2a81181066eb954966a487"),
},
];
for test_vector in TEST_VECTORS_128 {
test_vector.assert::<Sha256, U128>(DST, &dst_prime)?;
}
Ok(())
}
#[test]
fn expand_message_xmd_sha_256_long() -> Result<()> {
const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA256-128-long-DST-1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
const DST_PRIME: &[u8] =
&hex!("412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620");
let dst_prime = Domain::xmd::<Sha256>(&[DST])?;
dst_prime.assert_dst(DST_PRIME);
const TEST_VECTORS_32: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("e8dc0c8b686b7ef2074086fbdd2f30e3f8bfbd3bdf177f73f04b97ce618a3ed3"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("52dbf4f36cf560fca57dedec2ad924ee9c266341d8f3d6afe5171733b16bbb12"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("35387dcf22618f3728e6c686490f8b431f76550b0b2c61cbc1ce7001536f4521"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("01b637612bb18e840028be900a833a74414140dde0c4754c198532c3a0ba42bc"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("20cce7033cabc5460743180be6fa8aac5a103f56d481cf369a8accc0c374431b"),
},
];
for test_vector in TEST_VECTORS_32 {
test_vector.assert::<Sha256, U32>(DST, &dst_prime)?;
}
const TEST_VECTORS_128: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("14604d85432c68b757e485c8894db3117992fc57e0e136f71ad987f789a0abc287c47876978e2388a02af86b1e8d1342e5ce4f7aaa07a87321e691f6fba7e0072eecc1218aebb89fb14a0662322d5edbd873f0eb35260145cd4e64f748c5dfe60567e126604bcab1a3ee2dc0778102ae8a5cfd1429ebc0fa6bf1a53c36f55dfc"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("1a30a5e36fbdb87077552b9d18b9f0aee16e80181d5b951d0471d55b66684914aef87dbb3626eaabf5ded8cd0686567e503853e5c84c259ba0efc37f71c839da2129fe81afdaec7fbdc0ccd4c794727a17c0d20ff0ea55e1389d6982d1241cb8d165762dbc39fb0cee4474d2cbbd468a835ae5b2f20e4f959f56ab24cd6fe267"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("d2ecef3635d2397f34a9f86438d772db19ffe9924e28a1caf6f1c8f15603d4028f40891044e5c7e39ebb9b31339979ff33a4249206f67d4a1e7c765410bcd249ad78d407e303675918f20f26ce6d7027ed3774512ef5b00d816e51bfcc96c3539601fa48ef1c07e494bdc37054ba96ecb9dbd666417e3de289d4f424f502a982"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("ed6e8c036df90111410431431a232d41a32c86e296c05d426e5f44e75b9a50d335b2412bc6c91e0a6dc131de09c43110d9180d0a70f0d6289cb4e43b05f7ee5e9b3f42a1fad0f31bac6a625b3b5c50e3a83316783b649e5ecc9d3b1d9471cb5024b7ccf40d41d1751a04ca0356548bc6e703fca02ab521b505e8e45600508d32"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"),
uniform_bytes: &hex!("78b53f2413f3c688f07732c10e5ced29a17c6a16f717179ffbe38d92d6c9ec296502eb9889af83a1928cd162e845b0d3c5424e83280fed3d10cffb2f8431f14e7a23f4c68819d40617589e4c41169d0b56e0e3535be1fd71fbb08bb70c5b5ffed953d6c14bf7618b35fc1f4c4b30538236b4b08c9fbf90462447a8ada60be495"),
},
];
for test_vector in TEST_VECTORS_128 {
test_vector.assert::<Sha256, U128>(DST, &dst_prime)?;
}
Ok(())
}
#[test]
fn expand_message_xmd_sha_512() -> Result<()> {
use sha2::Sha512;
const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA512-256";
const DST_PRIME: &[u8] =
&hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626");
let dst_prime = Domain::xmd::<Sha512>(&[DST])?;
dst_prime.assert_dst(DST_PRIME);
const TEST_VECTORS_32: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("6b9a7312411d92f921c6f68ca0b6380730a1a4d982c507211a90964c394179ba"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("0da749f12fbe5483eb066a5f595055679b976e93abe9be6f0f6318bce7aca8dc"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("087e45a86e2939ee8b91100af1583c4938e0f5fc6c9db4b107b83346bc967f58"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("7336234ee9983902440f6bc35b348352013becd88938d2afec44311caf8356b3"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("57b5f7e766d5be68a6bfe1768e3c2b7f1228b3e4b3134956dd73a59b954c66f4"),
},
];
for test_vector in TEST_VECTORS_32 {
test_vector.assert::<Sha512, U32>(DST, &dst_prime)?;
}
const TEST_VECTORS_128: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("41b037d1734a5f8df225dd8c7de38f851efdb45c372887be655212d07251b921b052b62eaed99b46f72f2ef4cc96bfaf254ebbbec091e1a3b9e4fb5e5b619d2e0c5414800a1d882b62bb5cd1778f098b8eb6cb399d5d9d18f5d5842cf5d13d7eb00a7cff859b605da678b318bd0e65ebff70bec88c753b159a805d2c89c55961"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("7f1dddd13c08b543f2e2037b14cefb255b44c83cc397c1786d975653e36a6b11bdd7732d8b38adb4a0edc26a0cef4bb45217135456e58fbca1703cd6032cb1347ee720b87972d63fbf232587043ed2901bce7f22610c0419751c065922b488431851041310ad659e4b23520e1772ab29dcdeb2002222a363f0c2b1c972b3efe1"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("3f721f208e6199fe903545abc26c837ce59ac6fa45733f1baaf0222f8b7acb0424814fcb5eecf6c1d38f06e9d0a6ccfbf85ae612ab8735dfdf9ce84c372a77c8f9e1c1e952c3a61b7567dd0693016af51d2745822663d0c2367e3f4f0bed827feecc2aaf98c949b5ed0d35c3f1023d64ad1407924288d366ea159f46287e61ac"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("b799b045a58c8d2b4334cf54b78260b45eec544f9f2fb5bd12fb603eaee70db7317bf807c406e26373922b7b8920fa29142703dd52bdf280084fb7ef69da78afdf80b3586395b433dc66cde048a258e476a561e9deba7060af40adf30c64249ca7ddea79806ee5beb9a1422949471d267b21bc88e688e4014087a0b592b695ed"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"),
uniform_bytes: &hex!("05b0bfef265dcee87654372777b7c44177e2ae4c13a27f103340d9cd11c86cb2426ffcad5bd964080c2aee97f03be1ca18e30a1f14e27bc11ebbd650f305269cc9fb1db08bf90bfc79b42a952b46daf810359e7bc36452684784a64952c343c52e5124cd1f71d474d5197fefc571a92929c9084ffe1112cf5eea5192ebff330b"),
},
];
for test_vector in TEST_VECTORS_128 {
test_vector.assert::<Sha512, U128>(DST, &dst_prime)?;
}
Ok(())
}
}

View File

@@ -0,0 +1,348 @@
//! `expand_message_xof` for the `ExpandMsg` trait
use super::{Domain, ExpandMsg, Expander};
use crate::{Error, Result};
use digest::{ExtendableOutput, Update, XofReader};
use generic_array::typenum::U32;
/// Placeholder type for implementing `expand_message_xof` based on an extendable output function
///
/// # Errors
/// - `dst.is_empty()`
/// - `len_in_bytes == 0`
/// - `len_in_bytes > u16::MAX`
pub struct ExpandMsgXof<HashT>
where
HashT: Default + ExtendableOutput + Update,
{
reader: <HashT as ExtendableOutput>::Reader,
}
/// ExpandMsgXof implements `expand_message_xof` for the [`ExpandMsg`] trait
impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXof<HashT>
where
HashT: Default + ExtendableOutput + Update,
{
type Expander = Self;
fn expand_message(
msgs: &[&[u8]],
dsts: &'a [&'a [u8]],
len_in_bytes: usize,
) -> Result<Self::Expander> {
if len_in_bytes == 0 {
return Err(Error);
}
let len_in_bytes = u16::try_from(len_in_bytes).map_err(|_| Error)?;
let domain = Domain::<U32>::xof::<HashT>(dsts)?;
let mut reader = HashT::default();
for msg in msgs {
reader = reader.chain(msg);
}
reader.update(&len_in_bytes.to_be_bytes());
domain.update_hash(&mut reader);
reader.update(&[domain.len()]);
let reader = reader.finalize_xof();
Ok(Self { reader })
}
}
impl<HashT> Expander for ExpandMsgXof<HashT>
where
HashT: Default + ExtendableOutput + Update,
{
fn fill_bytes(&mut self, okm: &mut [u8]) {
self.reader.read(okm);
}
}
#[cfg(test)]
mod test {
use super::*;
use core::mem;
use generic_array::{
typenum::{U128, U32},
ArrayLength, GenericArray,
};
use hex_literal::hex;
use sha3::Shake128;
fn assert_message(msg: &[u8], domain: &Domain<'_, U32>, len_in_bytes: u16, bytes: &[u8]) {
let msg_len = msg.len();
assert_eq!(msg, &bytes[..msg_len]);
let len_in_bytes_len = msg_len + mem::size_of::<u16>();
assert_eq!(
len_in_bytes.to_be_bytes(),
&bytes[msg_len..len_in_bytes_len]
);
let dst = len_in_bytes_len + usize::from(domain.len());
domain.assert(&bytes[len_in_bytes_len..dst]);
let dst_len = dst + mem::size_of::<u8>();
assert_eq!([domain.len()], &bytes[dst..dst_len]);
assert_eq!(dst_len, bytes.len());
}
struct TestVector {
msg: &'static [u8],
msg_prime: &'static [u8],
uniform_bytes: &'static [u8],
}
impl TestVector {
#[allow(clippy::panic_in_result_fn)]
fn assert<HashT, L>(&self, dst: &'static [u8], domain: &Domain<'_, U32>) -> Result<()>
where
HashT: Default + ExtendableOutput + Update,
L: ArrayLength<u8>,
{
assert_message(self.msg, domain, L::to_u16(), self.msg_prime);
let mut expander =
ExpandMsgXof::<HashT>::expand_message(&[self.msg], &[dst], L::to_usize())?;
let mut uniform_bytes = GenericArray::<u8, L>::default();
expander.fill_bytes(&mut uniform_bytes);
assert_eq!(uniform_bytes.as_slice(), self.uniform_bytes);
Ok(())
}
}
#[test]
fn expand_message_xof_shake_128() -> Result<()> {
const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE128";
const DST_PRIME: &[u8] =
&hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824");
let dst_prime = Domain::<U32>::xof::<Shake128>(&[DST])?;
dst_prime.assert_dst(DST_PRIME);
const TEST_VECTORS_32: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("0020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("86518c9cd86581486e9485aa74ab35ba150d1c75c88e26b7043e44e2acd735a2"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("6162630020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("8696af52a4d862417c0763556073f47bc9b9ba43c99b505305cb1ec04a9ab468"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("616263646566303132333435363738390020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("912c58deac4821c3509dbefa094df54b34b8f5d01a191d1d3108a2c89077acca"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("1adbcc448aef2a0cebc71dac9f756b22e51839d348e031e63b33ebb50faeaf3f"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("df3447cc5f3e9a77da10f819218ddf31342c310778e0e4ef72bbaecee786a4fe"),
},
];
for test_vector in TEST_VECTORS_32 {
test_vector.assert::<Shake128, U32>(DST, &dst_prime)?;
}
const TEST_VECTORS_128: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("0080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("7314ff1a155a2fb99a0171dc71b89ab6e3b2b7d59e38e64419b8b6294d03ffee42491f11370261f436220ef787f8f76f5b26bdcd850071920ce023f3ac46847744f4612b8714db8f5db83205b2e625d95afd7d7b4d3094d3bdde815f52850bb41ead9822e08f22cf41d615a303b0d9dde73263c049a7b9898208003a739a2e57"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("6162630080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("c952f0c8e529ca8824acc6a4cab0e782fc3648c563ddb00da7399f2ae35654f4860ec671db2356ba7baa55a34a9d7f79197b60ddae6e64768a37d699a78323496db3878c8d64d909d0f8a7de4927dcab0d3dbbc26cb20a49eceb0530b431cdf47bc8c0fa3e0d88f53b318b6739fbed7d7634974f1b5c386d6230c76260d5337a"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("616263646566303132333435363738390080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("19b65ee7afec6ac06a144f2d6134f08eeec185f1a890fe34e68f0e377b7d0312883c048d9b8a1d6ecc3b541cb4987c26f45e0c82691ea299b5e6889bbfe589153016d8131717ba26f07c3c14ffbef1f3eff9752e5b6183f43871a78219a75e7000fbac6a7072e2b83c790a3a5aecd9d14be79f9fd4fb180960a3772e08680495"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("ca1b56861482b16eae0f4a26212112362fcc2d76dcc80c93c4182ed66c5113fe41733ed68be2942a3487394317f3379856f4822a611735e50528a60e7ade8ec8c71670fec6661e2c59a09ed36386513221688b35dc47e3c3111ee8c67ff49579089d661caa29db1ef10eb6eace575bf3dc9806e7c4016bd50f3c0e2a6481ee6d"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"),
uniform_bytes: &hex!("9d763a5ce58f65c91531b4100c7266d479a5d9777ba761693d052acd37d149e7ac91c796a10b919cd74a591a1e38719fb91b7203e2af31eac3bff7ead2c195af7d88b8bc0a8adf3d1e90ab9bed6ddc2b7f655dd86c730bdeaea884e73741097142c92f0e3fc1811b699ba593c7fbd81da288a29d423df831652e3a01a9374999"),
},
];
for test_vector in TEST_VECTORS_128 {
test_vector.assert::<Shake128, U128>(DST, &dst_prime)?;
}
Ok(())
}
#[test]
fn expand_message_xof_shake_128_long() -> Result<()> {
const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE128-long-DST-111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
const DST_PRIME: &[u8] =
&hex!("acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20");
let dst_prime = Domain::<U32>::xof::<Shake128>(&[DST])?;
dst_prime.assert_dst(DST_PRIME);
const TEST_VECTORS_32: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("0020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("827c6216330a122352312bccc0c8d6e7a146c5257a776dbd9ad9d75cd880fc53"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("6162630020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("690c8d82c7213b4282c6cb41c00e31ea1d3e2005f93ad19bbf6da40f15790c5c"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("616263646566303132333435363738390020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("979e3a15064afbbcf99f62cc09fa9c85028afcf3f825eb0711894dcfc2f57057"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("c5a9220962d9edc212c063f4f65b609755a1ed96e62f9db5d1fd6adb5a8dc52b"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("f7b96a5901af5d78ce1d071d9c383cac66a1dfadb508300ec6aeaea0d62d5d62"),
},
];
for test_vector in TEST_VECTORS_32 {
test_vector.assert::<Shake128, U32>(DST, &dst_prime)?;
}
const TEST_VECTORS_128: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("0080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("3890dbab00a2830be398524b71c2713bbef5f4884ac2e6f070b092effdb19208c7df943dc5dcbaee3094a78c267ef276632ee2c8ea0c05363c94b6348500fae4208345dd3475fe0c834c2beac7fa7bc181692fb728c0a53d809fc8111495222ce0f38468b11becb15b32060218e285c57a60162c2c8bb5b6bded13973cd41819"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("6162630080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("41b7ffa7a301b5c1441495ebb9774e2a53dbbf4e54b9a1af6a20fd41eafd69ef7b9418599c5545b1ee422f363642b01d4a53449313f68da3e49dddb9cd25b97465170537d45dcbdf92391b5bdff344db4bd06311a05bca7dcd360b6caec849c299133e5c9194f4e15e3e23cfaab4003fab776f6ac0bfae9144c6e2e1c62e7d57"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("616263646566303132333435363738390080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("55317e4a21318472cd2290c3082957e1242241d9e0d04f47026f03401643131401071f01aa03038b2783e795bdfa8a3541c194ad5de7cb9c225133e24af6c86e748deb52e560569bd54ef4dac03465111a3a44b0ea490fb36777ff8ea9f1a8a3e8e0de3cf0880b4b2f8dd37d3a85a8b82375aee4fa0e909f9763319b55778e71"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("19fdd2639f082e31c77717ac9bb032a22ff0958382b2dbb39020cdc78f0da43305414806abf9a561cb2d0067eb2f7bc544482f75623438ed4b4e39dd9e6e2909dd858bd8f1d57cd0fce2d3150d90aa67b4498bdf2df98c0100dd1a173436ba5d0df6be1defb0b2ce55ccd2f4fc05eb7cb2c019c35d5398b85adc676da4238bc7"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"),
uniform_bytes: &hex!("945373f0b3431a103333ba6a0a34f1efab2702efde41754c4cb1d5216d5b0a92a67458d968562bde7fa6310a83f53dda1383680a276a283438d58ceebfa7ab7ba72499d4a3eddc860595f63c93b1c5e823ea41fc490d938398a26db28f61857698553e93f0574eb8c5017bfed6249491f9976aaa8d23d9485339cc85ca329308"),
},
];
for test_vector in TEST_VECTORS_128 {
test_vector.assert::<Shake128, U128>(DST, &dst_prime)?;
}
Ok(())
}
#[test]
fn expand_message_xof_shake_256() -> Result<()> {
use sha3::Shake256;
const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE256";
const DST_PRIME: &[u8] =
&hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624");
let dst_prime = Domain::<U32>::xof::<Shake256>(&[DST])?;
dst_prime.assert_dst(DST_PRIME);
const TEST_VECTORS_32: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("0020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("2ffc05c48ed32b95d72e807f6eab9f7530dd1c2f013914c8fed38c5ccc15ad76"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("6162630020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("b39e493867e2767216792abce1f2676c197c0692aed061560ead251821808e07"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("616263646566303132333435363738390020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("245389cf44a13f0e70af8665fe5337ec2dcd138890bb7901c4ad9cfceb054b65"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("719b3911821e6428a5ed9b8e600f2866bcf23c8f0515e52d6c6c019a03f16f0e"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("9181ead5220b1963f1b5951f35547a5ea86a820562287d6ca4723633d17ccbbc"),
},
];
for test_vector in TEST_VECTORS_32 {
test_vector.assert::<Shake256, U32>(DST, &dst_prime)?;
}
const TEST_VECTORS_128: &[TestVector] = &[
TestVector {
msg: b"",
msg_prime: &hex!("0080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("7a1361d2d7d82d79e035b8880c5a3c86c5afa719478c007d96e6c88737a3f631dd74a2c88df79a4cb5e5d9f7504957c70d669ec6bfedc31e01e2bacc4ff3fdf9b6a00b17cc18d9d72ace7d6b81c2e481b4f73f34f9a7505dccbe8f5485f3d20c5409b0310093d5d6492dea4e18aa6979c23c8ea5de01582e9689612afbb353df"),
},
TestVector {
msg: b"abc",
msg_prime: &hex!("6162630080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("a54303e6b172909783353ab05ef08dd435a558c3197db0c132134649708e0b9b4e34fb99b92a9e9e28fc1f1d8860d85897a8e021e6382f3eea10577f968ff6df6c45fe624ce65ca25932f679a42a404bc3681efe03fcd45ef73bb3a8f79ba784f80f55ea8a3c367408f30381299617f50c8cf8fbb21d0f1e1d70b0131a7b6fbe"),
},
TestVector {
msg: b"abcdef0123456789",
msg_prime: &hex!("616263646566303132333435363738390080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("e42e4d9538a189316e3154b821c1bafb390f78b2f010ea404e6ac063deb8c0852fcd412e098e231e43427bd2be1330bb47b4039ad57b30ae1fc94e34993b162ff4d695e42d59d9777ea18d3848d9d336c25d2acb93adcad009bcfb9cde12286df267ada283063de0bb1505565b2eb6c90e31c48798ecdc71a71756a9110ff373"),
},
TestVector {
msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("4ac054dda0a38a65d0ecf7afd3c2812300027c8789655e47aecf1ecc1a2426b17444c7482c99e5907afd9c25b991990490bb9c686f43e79b4471a23a703d4b02f23c669737a886a7ec28bddb92c3a98de63ebf878aa363a501a60055c048bea11840c4717beae7eee28c3cfa42857b3d130188571943a7bd747de831bd6444e0"),
},
TestVector {
msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"),
uniform_bytes: &hex!("09afc76d51c2cccbc129c2315df66c2be7295a231203b8ab2dd7f95c2772c68e500bc72e20c602abc9964663b7a03a389be128c56971ce81001a0b875e7fd17822db9d69792ddf6a23a151bf470079c518279aef3e75611f8f828994a9988f4a8a256ddb8bae161e658d5a2a09bcfe839c6396dc06ee5c8ff3c22d3b1f9deb7e"),
},
];
for test_vector in TEST_VECTORS_128 {
test_vector.assert::<Shake256, U128>(DST, &dst_prime)?;
}
Ok(())
}
}

View File

@@ -0,0 +1,57 @@
//! Traits for mapping an isogeny to another curve
//!
//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve>
use core::ops::{AddAssign, Mul};
use ff::Field;
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
/// The coefficients for mapping from one isogenous curve to another
pub struct IsogenyCoefficients<F: Field + AddAssign + Mul<Output = F>> {
/// The coefficients for the x numerator
pub xnum: &'static [F],
/// The coefficients for the x denominator
pub xden: &'static [F],
/// The coefficients for the y numerator
pub ynum: &'static [F],
/// The coefficients for the x denominator
pub yden: &'static [F],
}
/// The [`Isogeny`] methods to map to another curve.
pub trait Isogeny: Field + AddAssign + Mul<Output = Self> {
/// The maximum number of coefficients
type Degree: ArrayLength<Self>;
/// The isogeny coefficients
const COEFFICIENTS: IsogenyCoefficients<Self>;
/// Map from the isogeny points to the main curve
fn isogeny(x: Self, y: Self) -> (Self, Self) {
let mut xs = GenericArray::<Self, Self::Degree>::default();
xs[0] = Self::ONE;
xs[1] = x;
xs[2] = x.square();
for i in 3..Self::Degree::to_usize() {
xs[i] = xs[i - 1] * x;
}
let x_num = Self::compute_iso(&xs, Self::COEFFICIENTS.xnum);
let x_den = Self::compute_iso(&xs, Self::COEFFICIENTS.xden)
.invert()
.unwrap();
let y_num = Self::compute_iso(&xs, Self::COEFFICIENTS.ynum) * y;
let y_den = Self::compute_iso(&xs, Self::COEFFICIENTS.yden)
.invert()
.unwrap();
(x_num * x_den, y_num * y_den)
}
/// Compute the ISO transform
fn compute_iso(xxs: &[Self], k: &[Self]) -> Self {
let mut xx = Self::ZERO;
for (xi, ki) in xxs.iter().zip(k.iter()) {
xx += *xi * ki;
}
xx
}
}

View File

@@ -0,0 +1,12 @@
//! Traits for mapping field elements to points on the curve.
/// Trait for converting field elements into a point
/// via a mapping method like Simplified Shallue-van de Woestijne-Ulas
/// or Elligator
pub trait MapToCurve {
/// The output point
type Output;
/// Map a field element into a point
fn map_to_curve(&self) -> Self::Output;
}

View File

@@ -0,0 +1,130 @@
//! Optimized simplified Shallue-van de Woestijne-Ulas methods.
//!
//! <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-sswu>
use ff::Field;
use subtle::Choice;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
/// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters
pub struct OsswuMapParams<F>
where
F: Field,
{
/// The first constant term
pub c1: &'static [u64],
/// The second constant term
pub c2: F,
/// The ISO A variable or Curve A variable
pub map_a: F,
/// The ISO A variable or Curve A variable
pub map_b: F,
/// The Z parameter
pub z: F,
}
/// Trait for determining the parity of the field
pub trait Sgn0 {
/// Return the parity of the field
/// 1 == negative
/// 0 == non-negative
fn sgn0(&self) -> Choice;
}
/// The optimized simplified Shallue-van de Woestijne-Ulas method
/// for mapping elliptic curve scalars to affine points.
pub trait OsswuMap: Field + Sgn0 {
/// The OSSWU parameters for mapping the field to affine points.
/// For Weierstrass curves having A==0 or B==0, the parameters
/// should be for isogeny where A≠0 and B≠0.
const PARAMS: OsswuMapParams<Self>;
/// Optimized sqrt_ratio for q = 3 mod 4.
fn sqrt_ratio_3mod4(u: Self, v: Self) -> (Choice, Self) {
// 1. tv1 = v^2
let tv1 = v.square();
// 2. tv2 = u * v
let tv2 = u * v;
// 3. tv1 = tv1 * tv2
let tv1 = tv1 * tv2;
// 4. y1 = tv1^c1
let y1 = tv1.pow_vartime(Self::PARAMS.c1);
// 5. y1 = y1 * tv2
let y1 = y1 * tv2;
// 6. y2 = y1 * c2
let y2 = y1 * Self::PARAMS.c2;
// 7. tv3 = y1^2
let tv3 = y1.square();
// 8. tv3 = tv3 * v
let tv3 = tv3 * v;
// 9. isQR = tv3 == u
let is_qr = tv3.ct_eq(&u);
// 10. y = CMOV(y2, y1, isQR)
let y = ConditionallySelectable::conditional_select(&y2, &y1, is_qr);
// 11. return (isQR, y)
(is_qr, y)
}
/// Convert this field element into an affine point on the elliptic curve
/// returning (X, Y). For Weierstrass curves having A==0 or B==0
/// the result is a point on an isogeny.
fn osswu(&self) -> (Self, Self) {
// 1. tv1 = u^2
let tv1 = self.square();
// 2. tv1 = Z * tv1
let tv1 = Self::PARAMS.z * tv1;
// 3. tv2 = tv1^2
let tv2 = tv1.square();
// 4. tv2 = tv2 + tv1
let tv2 = tv2 + tv1;
// 5. tv3 = tv2 + 1
let tv3 = tv2 + Self::ONE;
// 6. tv3 = B * tv3
let tv3 = Self::PARAMS.map_b * tv3;
// 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
let tv4 = ConditionallySelectable::conditional_select(
&Self::PARAMS.z,
&-tv2,
!Field::is_zero(&tv2),
);
// 8. tv4 = A * tv4
let tv4 = Self::PARAMS.map_a * tv4;
// 9. tv2 = tv3^2
let tv2 = tv3.square();
// 10. tv6 = tv4^2
let tv6 = tv4.square();
// 11. tv5 = A * tv6
let tv5 = Self::PARAMS.map_a * tv6;
// 12. tv2 = tv2 + tv5
let tv2 = tv2 + tv5;
// 13. tv2 = tv2 * tv3
let tv2 = tv2 * tv3;
// 14. tv6 = tv6 * tv4
let tv6 = tv6 * tv4;
// 15. tv5 = B * tv6
let tv5 = Self::PARAMS.map_b * tv6;
// 16. tv2 = tv2 + tv5
let tv2 = tv2 + tv5;
// 17. x = tv1 * tv3
let x = tv1 * tv3;
// 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
let (is_gx1_square, y1) = Self::sqrt_ratio_3mod4(tv2, tv6);
// 19. y = tv1 * u
let y = tv1 * self;
// 20. y = y * y1
let y = y * y1;
// 21. x = CMOV(x, tv3, is_gx1_square)
let x = ConditionallySelectable::conditional_select(&x, &tv3, is_gx1_square);
// 22. y = CMOV(y, y1, is_gx1_square)
let y = ConditionallySelectable::conditional_select(&y, &y1, is_gx1_square);
// 23. e1 = sgn0(u) == sgn0(y)
let e1 = self.sgn0().ct_eq(&y.sgn0());
// 24. y = CMOV(-y, y, e1)
let y = ConditionallySelectable::conditional_select(&-y, &y, e1);
// 25. x = x / tv4
let x = x * tv4.invert().unwrap();
// 26. return (x, y)
(x, y)
}
}

675
vendor/elliptic-curve/src/jwk.rs vendored Normal file
View File

@@ -0,0 +1,675 @@
//! JSON Web Key (JWK) Support.
//!
//! Specified in RFC 7518 Section 6: Cryptographic Algorithms for Keys:
//! <https://tools.ietf.org/html/rfc7518#section-6>
use crate::{
sec1::{Coordinates, EncodedPoint, ModulusSize, ValidatePublicKey},
secret_key::SecretKey,
Curve, Error, FieldBytes, FieldBytesSize, Result,
};
use alloc::{
borrow::ToOwned,
format,
string::{String, ToString},
};
use base64ct::{Base64UrlUnpadded as Base64Url, Encoding};
use core::{
fmt::{self, Debug},
marker::PhantomData,
str::{self, FromStr},
};
use serdect::serde::{de, ser, Deserialize, Serialize};
use zeroize::{Zeroize, ZeroizeOnDrop};
#[cfg(feature = "arithmetic")]
use crate::{
public_key::PublicKey,
sec1::{FromEncodedPoint, ToEncodedPoint},
AffinePoint, CurveArithmetic,
};
/// Key Type (`kty`) for elliptic curve keys.
pub const EC_KTY: &str = "EC";
/// Deserialization error message.
const DE_ERROR_MSG: &str = "struct JwkEcKey with 5 elements";
/// Name of the JWK type
const JWK_TYPE_NAME: &str = "JwkEcKey";
/// Field names
const FIELDS: &[&str] = &["kty", "crv", "x", "y", "d"];
/// Elliptic curve parameters used by JSON Web Keys.
pub trait JwkParameters: Curve {
/// The `crv` parameter which identifies a particular elliptic curve
/// as defined in RFC 7518 Section 6.2.1.1:
/// <https://tools.ietf.org/html/rfc7518#section-6.2.1.1>
///
/// Curve values are registered in the IANA "JSON Web Key Elliptic Curve"
/// registry defined in RFC 7518 Section 7.6:
/// <https://tools.ietf.org/html/rfc7518#section-7.6>
const CRV: &'static str;
}
/// JSON Web Key (JWK) with a `kty` of `"EC"` (elliptic curve).
///
/// Specified in [RFC 7518 Section 6: Cryptographic Algorithms for Keys][1].
///
/// This type can represent either a public/private keypair, or just a
/// public key, depending on whether or not the `d` parameter is present.
///
/// [1]: https://tools.ietf.org/html/rfc7518#section-6
// TODO(tarcieri): eagerly decode or validate `x`, `y`, and `d` as Base64
#[derive(Clone)]
pub struct JwkEcKey {
/// The `crv` parameter which identifies a particular elliptic curve
/// as defined in RFC 7518 Section 6.2.1.1:
/// <https://tools.ietf.org/html/rfc7518#section-6.2.1.1>
crv: String,
/// The x-coordinate of the elliptic curve point which is the public key
/// value associated with this JWK as defined in RFC 7518 6.2.1.2:
/// <https://tools.ietf.org/html/rfc7518#section-6.2.1.2>
x: String,
/// The y-coordinate of the elliptic curve point which is the public key
/// value associated with this JWK as defined in RFC 7518 6.2.1.3:
/// <https://tools.ietf.org/html/rfc7518#section-6.2.1.3>
y: String,
/// The `d` ECC private key parameter as described in RFC 7518 6.2.2.1:
/// <https://tools.ietf.org/html/rfc7518#section-6.2.2.1>
///
/// Value is optional and if omitted, this JWK represents a private key.
///
/// Inner value is encoded according to the `Integer-to-Octet-String`
/// conversion as defined in SEC1 section 2.3.7:
/// <https://www.secg.org/sec1-v2.pdf>
d: Option<String>,
}
impl JwkEcKey {
/// Get the `crv` parameter for this JWK.
pub fn crv(&self) -> &str {
&self.crv
}
/// Is this JWK a keypair that includes a private key?
pub fn is_keypair(&self) -> bool {
self.d.is_some()
}
/// Does this JWK contain only a public key?
pub fn is_public_key(&self) -> bool {
self.d.is_none()
}
/// Decode a JWK into a [`PublicKey`].
#[cfg(feature = "arithmetic")]
pub fn to_public_key<C>(&self) -> Result<PublicKey<C>>
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
PublicKey::from_sec1_bytes(self.to_encoded_point::<C>()?.as_bytes())
}
/// Create a JWK from a SEC1 [`EncodedPoint`].
pub fn from_encoded_point<C>(point: &EncodedPoint<C>) -> Option<Self>
where
C: Curve + JwkParameters,
FieldBytesSize<C>: ModulusSize,
{
match point.coordinates() {
Coordinates::Uncompressed { x, y } => Some(JwkEcKey {
crv: C::CRV.to_owned(),
x: Base64Url::encode_string(x),
y: Base64Url::encode_string(y),
d: None,
}),
_ => None,
}
}
/// Get the public key component of this JWK as a SEC1 [`EncodedPoint`].
pub fn to_encoded_point<C>(&self) -> Result<EncodedPoint<C>>
where
C: Curve + JwkParameters,
FieldBytesSize<C>: ModulusSize,
{
if self.crv != C::CRV {
return Err(Error);
}
let x = decode_base64url_fe::<C>(&self.x)?;
let y = decode_base64url_fe::<C>(&self.y)?;
Ok(EncodedPoint::<C>::from_affine_coordinates(&x, &y, false))
}
/// Decode a JWK into a [`SecretKey`].
#[cfg(feature = "arithmetic")]
pub fn to_secret_key<C>(&self) -> Result<SecretKey<C>>
where
C: Curve + JwkParameters + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
self.try_into()
}
}
impl FromStr for JwkEcKey {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
serde_json::from_str(s).map_err(|_| Error)
}
}
impl ToString for JwkEcKey {
fn to_string(&self) -> String {
serde_json::to_string(self).expect("JWK encoding error")
}
}
impl<C> TryFrom<JwkEcKey> for SecretKey<C>
where
C: Curve + JwkParameters + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
type Error = Error;
fn try_from(jwk: JwkEcKey) -> Result<SecretKey<C>> {
(&jwk).try_into()
}
}
impl<C> TryFrom<&JwkEcKey> for SecretKey<C>
where
C: Curve + JwkParameters + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
type Error = Error;
fn try_from(jwk: &JwkEcKey) -> Result<SecretKey<C>> {
if let Some(d_base64) = &jwk.d {
let pk = jwk.to_encoded_point::<C>()?;
let mut d_bytes = decode_base64url_fe::<C>(d_base64)?;
let result = SecretKey::from_slice(&d_bytes);
d_bytes.zeroize();
result.and_then(|secret_key| {
C::validate_public_key(&secret_key, &pk)?;
Ok(secret_key)
})
} else {
Err(Error)
}
}
}
#[cfg(feature = "arithmetic")]
impl<C> From<SecretKey<C>> for JwkEcKey
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn from(sk: SecretKey<C>) -> JwkEcKey {
(&sk).into()
}
}
#[cfg(feature = "arithmetic")]
impl<C> From<&SecretKey<C>> for JwkEcKey
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn from(sk: &SecretKey<C>) -> JwkEcKey {
let mut jwk = sk.public_key().to_jwk();
let mut d = sk.to_bytes();
jwk.d = Some(Base64Url::encode_string(&d));
d.zeroize();
jwk
}
}
#[cfg(feature = "arithmetic")]
impl<C> TryFrom<JwkEcKey> for PublicKey<C>
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
type Error = Error;
fn try_from(jwk: JwkEcKey) -> Result<PublicKey<C>> {
(&jwk).try_into()
}
}
#[cfg(feature = "arithmetic")]
impl<C> TryFrom<&JwkEcKey> for PublicKey<C>
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
type Error = Error;
fn try_from(jwk: &JwkEcKey) -> Result<PublicKey<C>> {
PublicKey::from_sec1_bytes(jwk.to_encoded_point::<C>()?.as_bytes())
}
}
#[cfg(feature = "arithmetic")]
impl<C> From<PublicKey<C>> for JwkEcKey
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn from(pk: PublicKey<C>) -> JwkEcKey {
(&pk).into()
}
}
#[cfg(feature = "arithmetic")]
impl<C> From<&PublicKey<C>> for JwkEcKey
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn from(pk: &PublicKey<C>) -> JwkEcKey {
Self::from_encoded_point::<C>(&pk.to_encoded_point(false)).expect("JWK encoding error")
}
}
impl Debug for JwkEcKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let d = if self.d.is_some() {
"Some(...)"
} else {
"None"
};
// NOTE: this implementation omits the `d` private key parameter
f.debug_struct(JWK_TYPE_NAME)
.field("crv", &self.crv)
.field("x", &self.x)
.field("y", &self.y)
.field("d", &d)
.finish()
}
}
impl PartialEq for JwkEcKey {
fn eq(&self, other: &Self) -> bool {
use subtle::ConstantTimeEq;
// Compare private key in constant time
let d_eq = match &self.d {
Some(d1) => match &other.d {
Some(d2) => d1.as_bytes().ct_eq(d2.as_bytes()).into(),
None => other.d.is_none(),
},
None => other.d.is_none(),
};
self.crv == other.crv && self.x == other.x && self.y == other.y && d_eq
}
}
impl Eq for JwkEcKey {}
impl ZeroizeOnDrop for JwkEcKey {}
impl Drop for JwkEcKey {
fn drop(&mut self) {
self.zeroize();
}
}
impl Zeroize for JwkEcKey {
fn zeroize(&mut self) {
if let Some(d) = &mut self.d {
d.zeroize();
}
}
}
impl<'de> Deserialize<'de> for JwkEcKey {
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
/// Field positions
enum Field {
Kty,
Crv,
X,
Y,
D,
}
/// Field visitor
struct FieldVisitor;
impl<'de> de::Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Formatter::write_str(formatter, "field identifier")
}
fn visit_u64<E>(self, value: u64) -> core::result::Result<Self::Value, E>
where
E: de::Error,
{
match value {
0 => Ok(Field::Kty),
1 => Ok(Field::Crv),
2 => Ok(Field::X),
3 => Ok(Field::Y),
4 => Ok(Field::D),
_ => Err(de::Error::invalid_value(
de::Unexpected::Unsigned(value),
&"field index 0 <= i < 5",
)),
}
}
fn visit_str<E>(self, value: &str) -> core::result::Result<Self::Value, E>
where
E: de::Error,
{
self.visit_bytes(value.as_bytes())
}
fn visit_bytes<E>(self, value: &[u8]) -> core::result::Result<Self::Value, E>
where
E: de::Error,
{
match value {
b"kty" => Ok(Field::Kty),
b"crv" => Ok(Field::Crv),
b"x" => Ok(Field::X),
b"y" => Ok(Field::Y),
b"d" => Ok(Field::D),
_ => Err(de::Error::unknown_field(
&String::from_utf8_lossy(value),
FIELDS,
)),
}
}
}
impl<'de> Deserialize<'de> for Field {
#[inline]
fn deserialize<D>(__deserializer: D) -> core::result::Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
de::Deserializer::deserialize_identifier(__deserializer, FieldVisitor)
}
}
struct Visitor<'de> {
marker: PhantomData<JwkEcKey>,
lifetime: PhantomData<&'de ()>,
}
impl<'de> de::Visitor<'de> for Visitor<'de> {
type Value = JwkEcKey;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Formatter::write_str(formatter, "struct JwkEcKey")
}
#[inline]
fn visit_seq<A>(self, mut seq: A) -> core::result::Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let kty = de::SeqAccess::next_element::<String>(&mut seq)?
.ok_or_else(|| de::Error::invalid_length(0, &DE_ERROR_MSG))?;
if kty != EC_KTY {
return Err(de::Error::custom(format!("unsupported JWK kty: {kty:?}")));
}
let crv = de::SeqAccess::next_element::<String>(&mut seq)?
.ok_or_else(|| de::Error::invalid_length(1, &DE_ERROR_MSG))?;
let x = de::SeqAccess::next_element::<String>(&mut seq)?
.ok_or_else(|| de::Error::invalid_length(2, &DE_ERROR_MSG))?;
let y = de::SeqAccess::next_element::<String>(&mut seq)?
.ok_or_else(|| de::Error::invalid_length(3, &DE_ERROR_MSG))?;
let d = de::SeqAccess::next_element::<Option<String>>(&mut seq)?
.ok_or_else(|| de::Error::invalid_length(4, &DE_ERROR_MSG))?;
Ok(JwkEcKey { crv, x, y, d })
}
#[inline]
fn visit_map<A>(self, mut map: A) -> core::result::Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>,
{
let mut kty: Option<String> = None;
let mut crv: Option<String> = None;
let mut x: Option<String> = None;
let mut y: Option<String> = None;
let mut d: Option<String> = None;
while let Some(key) = de::MapAccess::next_key::<Field>(&mut map)? {
match key {
Field::Kty => {
if kty.is_none() {
kty = Some(de::MapAccess::next_value::<String>(&mut map)?);
} else {
return Err(de::Error::duplicate_field(FIELDS[0]));
}
}
Field::Crv => {
if crv.is_none() {
crv = Some(de::MapAccess::next_value::<String>(&mut map)?);
} else {
return Err(de::Error::duplicate_field(FIELDS[1]));
}
}
Field::X => {
if x.is_none() {
x = Some(de::MapAccess::next_value::<String>(&mut map)?);
} else {
return Err(de::Error::duplicate_field(FIELDS[2]));
}
}
Field::Y => {
if y.is_none() {
y = Some(de::MapAccess::next_value::<String>(&mut map)?);
} else {
return Err(de::Error::duplicate_field(FIELDS[3]));
}
}
Field::D => {
if d.is_none() {
d = de::MapAccess::next_value::<Option<String>>(&mut map)?;
} else {
return Err(de::Error::duplicate_field(FIELDS[4]));
}
}
}
}
let kty = kty.ok_or_else(|| de::Error::missing_field("kty"))?;
if kty != EC_KTY {
return Err(de::Error::custom(format!("unsupported JWK kty: {kty}")));
}
let crv = crv.ok_or_else(|| de::Error::missing_field("crv"))?;
let x = x.ok_or_else(|| de::Error::missing_field("x"))?;
let y = y.ok_or_else(|| de::Error::missing_field("y"))?;
Ok(JwkEcKey { crv, x, y, d })
}
}
de::Deserializer::deserialize_struct(
deserializer,
JWK_TYPE_NAME,
FIELDS,
Visitor {
marker: PhantomData::<JwkEcKey>,
lifetime: PhantomData,
},
)
}
}
impl Serialize for JwkEcKey {
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
use ser::SerializeStruct;
let mut state = serializer.serialize_struct(JWK_TYPE_NAME, 5)?;
for (i, field) in [EC_KTY, &self.crv, &self.x, &self.y].iter().enumerate() {
state.serialize_field(FIELDS[i], field)?;
}
if let Some(d) = &self.d {
state.serialize_field("d", d)?;
}
ser::SerializeStruct::end(state)
}
}
/// Decode a Base64url-encoded field element
fn decode_base64url_fe<C: Curve>(s: &str) -> Result<FieldBytes<C>> {
let mut result = FieldBytes::<C>::default();
Base64Url::decode(s, &mut result).map_err(|_| Error)?;
Ok(result)
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::panic)]
use super::*;
#[cfg(feature = "dev")]
use crate::dev::MockCurve;
/// Example private key. From RFC 7518 Appendix C:
/// <https://tools.ietf.org/html/rfc7518#appendix-C>
const JWK_PRIVATE_KEY: &str = r#"
{
"kty":"EC",
"crv":"P-256",
"x":"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0",
"y":"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps",
"d":"0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo"
}
"#;
/// Example public key.
const JWK_PUBLIC_KEY: &str = r#"
{
"kty":"EC",
"crv":"P-256",
"x":"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0",
"y":"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"
}
"#;
/// Example unsupported JWK (RSA key)
const UNSUPPORTED_JWK: &str = r#"
{
"kty":"RSA",
"kid":"cc34c0a0-bd5a-4a3c-a50d-a2a7db7643df",
"use":"sig",
"n":"pjdss8ZaDfEH6K6U7GeW2nxDqR4IP049fk1fK0lndimbMMVBdPv_hSpm8T8EtBDxrUdi1OHZfMhUixGaut-3nQ4GG9nM249oxhCtxqqNvEXrmQRGqczyLxuh-fKn9Fg--hS9UpazHpfVAFnB5aCfXoNhPuI8oByyFKMKaOVgHNqP5NBEqabiLftZD3W_lsFCPGuzr4Vp0YS7zS2hDYScC2oOMu4rGU1LcMZf39p3153Cq7bS2Xh6Y-vw5pwzFYZdjQxDn8x8BG3fJ6j8TGLXQsbKH1218_HcUJRvMwdpbUQG5nvA2GXVqLqdwp054Lzk9_B_f1lVrmOKuHjTNHq48w",
"e":"AQAB",
"d":"ksDmucdMJXkFGZxiomNHnroOZxe8AmDLDGO1vhs-POa5PZM7mtUPonxwjVmthmpbZzla-kg55OFfO7YcXhg-Hm2OWTKwm73_rLh3JavaHjvBqsVKuorX3V3RYkSro6HyYIzFJ1Ek7sLxbjDRcDOj4ievSX0oN9l-JZhaDYlPlci5uJsoqro_YrE0PRRWVhtGynd-_aWgQv1YzkfZuMD-hJtDi1Im2humOWxA4eZrFs9eG-whXcOvaSwO4sSGbS99ecQZHM2TcdXeAs1PvjVgQ_dKnZlGN3lTWoWfQP55Z7Tgt8Nf1q4ZAKd-NlMe-7iqCFfsnFwXjSiaOa2CRGZn-Q",
"p":"4A5nU4ahEww7B65yuzmGeCUUi8ikWzv1C81pSyUKvKzu8CX41hp9J6oRaLGesKImYiuVQK47FhZ--wwfpRwHvSxtNU9qXb8ewo-BvadyO1eVrIk4tNV543QlSe7pQAoJGkxCia5rfznAE3InKF4JvIlchyqs0RQ8wx7lULqwnn0",
"q":"ven83GM6SfrmO-TBHbjTk6JhP_3CMsIvmSdo4KrbQNvp4vHO3w1_0zJ3URkmkYGhz2tgPlfd7v1l2I6QkIh4Bumdj6FyFZEBpxjE4MpfdNVcNINvVj87cLyTRmIcaGxmfylY7QErP8GFA-k4UoH_eQmGKGK44TRzYj5hZYGWIC8",
"dp":"lmmU_AG5SGxBhJqb8wxfNXDPJjf__i92BgJT2Vp4pskBbr5PGoyV0HbfUQVMnw977RONEurkR6O6gxZUeCclGt4kQlGZ-m0_XSWx13v9t9DIbheAtgVJ2mQyVDvK4m7aRYlEceFh0PsX8vYDS5o1txgPwb3oXkPTtrmbAGMUBpE",
"dq":"mxRTU3QDyR2EnCv0Nl0TCF90oliJGAHR9HJmBe__EjuCBbwHfcT8OG3hWOv8vpzokQPRl5cQt3NckzX3fs6xlJN4Ai2Hh2zduKFVQ2p-AF2p6Yfahscjtq-GY9cB85NxLy2IXCC0PF--Sq9LOrTE9QV988SJy_yUrAjcZ5MmECk",
"qi":"ldHXIrEmMZVaNwGzDF9WG8sHj2mOZmQpw9yrjLK9hAsmsNr5LTyqWAqJIYZSwPTYWhY4nu2O0EY9G9uYiqewXfCKw_UngrJt8Xwfq1Zruz0YY869zPN4GiE9-9rzdZB33RBw8kIOquY3MK74FMwCihYx_LiU2YTHkaoJ3ncvtvg"
}
"#;
#[test]
fn parse_private_key() {
let jwk = JwkEcKey::from_str(JWK_PRIVATE_KEY).unwrap();
assert_eq!(jwk.crv, "P-256");
assert_eq!(jwk.x, "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0");
assert_eq!(jwk.y, "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps");
assert_eq!(
jwk.d.as_ref().unwrap(),
"0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo"
);
}
#[test]
fn parse_public_key() {
let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap();
assert_eq!(jwk.crv, "P-256");
assert_eq!(jwk.x, "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0");
assert_eq!(jwk.y, "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps");
assert_eq!(jwk.d, None);
}
#[test]
fn parse_unsupported() {
assert_eq!(JwkEcKey::from_str(UNSUPPORTED_JWK), Err(Error));
}
#[test]
fn serialize_private_key() {
let actual = JwkEcKey::from_str(JWK_PRIVATE_KEY).unwrap().to_string();
let expected: String = JWK_PRIVATE_KEY.split_whitespace().collect();
assert_eq!(actual, expected);
}
#[test]
fn serialize_public_key() {
let actual = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap().to_string();
let expected: String = JWK_PUBLIC_KEY.split_whitespace().collect();
assert_eq!(actual, expected);
}
#[cfg(feature = "dev")]
#[test]
fn jwk_into_encoded_point() {
let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap();
let point = jwk.to_encoded_point::<MockCurve>().unwrap();
let (x, y) = match point.coordinates() {
Coordinates::Uncompressed { x, y } => (x, y),
other => panic!("unexpected coordinates: {other:?}"),
};
assert_eq!(&decode_base64url_fe::<MockCurve>(&jwk.x).unwrap(), x);
assert_eq!(&decode_base64url_fe::<MockCurve>(&jwk.y).unwrap(), y);
}
#[cfg(feature = "dev")]
#[test]
fn encoded_point_into_jwk() {
let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap();
let point = jwk.to_encoded_point::<MockCurve>().unwrap();
let jwk2 = JwkEcKey::from_encoded_point::<MockCurve>(&point).unwrap();
assert_eq!(jwk, jwk2);
}
}

196
vendor/elliptic-curve/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,196 @@
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
)]
#![forbid(unsafe_code)]
#![warn(
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::checked_conversions,
clippy::implicit_saturating_sub,
clippy::mod_module_files,
clippy::panic,
clippy::panic_in_result_fn,
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
//! ## Usage
//!
//! This crate provides traits for describing elliptic curves, along with
//! types which are generic over elliptic curves which can be used as the
//! basis of curve-agnostic code.
//!
//! It's intended to be used with the following concrete elliptic curve
//! implementations from the [`RustCrypto/elliptic-curves`] project:
//!
//! - [`bp256`]: brainpoolP256r1 and brainpoolP256t1
//! - [`bp384`]: brainpoolP384r1 and brainpoolP384t1
//! - [`k256`]: secp256k1 a.k.a. K-256
//! - [`p224`]: NIST P-224 a.k.a. secp224r1
//! - [`p256`]: NIST P-256 a.k.a secp256r1, prime256v1
//! - [`p384`]: NIST P-384 a.k.a. secp384r1
//! - [`p521`]: NIST P-521 a.k.a. secp521r1
//!
//! The [`ecdsa`] crate provides a generic implementation of the
//! Elliptic Curve Digital Signature Algorithm which can be used with any of
//! the above crates, either via an external ECDSA implementation, or
//! using native curve arithmetic where applicable.
//!
//! ## Type conversions
//!
//! The following chart illustrates the various conversions possible between
//! the various types defined by this crate.
//!
//! ![Type Conversion Map](https://raw.githubusercontent.com/RustCrypto/media/master/img/elliptic-curve/type-transforms.svg)
//!
//! ## `serde` support
//!
//! When the `serde` feature of this crate is enabled, `Serialize` and
//! `Deserialize` impls are provided for the following types:
//!
//! - [`JwkEcKey`]
//! - [`PublicKey`]
//! - [`ScalarPrimitive`]
//!
//! Please see type-specific documentation for more information.
//!
//! [`RustCrypto/elliptic-curves`]: https://github.com/RustCrypto/elliptic-curves
//! [`bp256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp256
//! [`bp384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp384
//! [`k256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/k256
//! [`p224`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p224
//! [`p256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256
//! [`p384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384
//! [`p521`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p521
//! [`ecdsa`]: https://github.com/RustCrypto/signatures/tree/master/ecdsa
#[cfg(feature = "alloc")]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
pub mod point;
pub mod scalar;
#[cfg(feature = "dev")]
pub mod dev;
#[cfg(feature = "ecdh")]
pub mod ecdh;
#[cfg(feature = "hash2curve")]
pub mod hash2curve;
#[cfg(feature = "arithmetic")]
pub mod ops;
#[cfg(feature = "sec1")]
pub mod sec1;
#[cfg(feature = "arithmetic")]
pub mod weierstrass;
mod error;
mod field;
mod secret_key;
#[cfg(feature = "arithmetic")]
mod arithmetic;
#[cfg(feature = "arithmetic")]
mod public_key;
#[cfg(feature = "jwk")]
mod jwk;
#[cfg(feature = "voprf")]
mod voprf;
pub use crate::{
error::{Error, Result},
field::{FieldBytes, FieldBytesEncoding, FieldBytesSize},
scalar::ScalarPrimitive,
secret_key::SecretKey,
};
pub use crypto_bigint as bigint;
pub use generic_array::{self, typenum::consts};
pub use rand_core;
pub use subtle;
pub use zeroize;
#[cfg(feature = "arithmetic")]
pub use {
crate::{
arithmetic::{CurveArithmetic, PrimeCurveArithmetic},
point::{AffinePoint, BatchNormalize, ProjectivePoint},
public_key::PublicKey,
scalar::{NonZeroScalar, Scalar},
},
ff::{self, Field, PrimeField},
group::{self, Group},
};
#[cfg(feature = "jwk")]
pub use crate::jwk::{JwkEcKey, JwkParameters};
#[cfg(feature = "pkcs8")]
pub use pkcs8;
#[cfg(feature = "voprf")]
pub use crate::voprf::VoprfParameters;
use core::{
fmt::Debug,
ops::{Add, ShrAssign},
};
use generic_array::ArrayLength;
/// Algorithm [`ObjectIdentifier`][`pkcs8::ObjectIdentifier`] for elliptic
/// curve public key cryptography (`id-ecPublicKey`).
///
/// <http://oid-info.com/get/1.2.840.10045.2.1>
#[cfg(feature = "pkcs8")]
pub const ALGORITHM_OID: pkcs8::ObjectIdentifier =
pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.2.1");
/// Elliptic curve.
///
/// This trait is intended to be impl'd by a ZST which represents a concrete
/// elliptic curve.
///
/// Other traits in this crate which are bounded by [`Curve`] are intended to
/// be impl'd by these ZSTs, facilitating types which are generic over elliptic
/// curves (e.g. [`SecretKey`]).
pub trait Curve: 'static + Copy + Clone + Debug + Default + Eq + Ord + Send + Sync {
/// Size of a serialized field element in bytes.
///
/// This is typically the same as `Self::Uint::ByteSize` but for curves
/// with an unusual field modulus (e.g. P-224, P-521) it may be different.
type FieldBytesSize: ArrayLength<u8> + Add + Eq;
/// Integer type used to represent field elements of this elliptic curve.
type Uint: bigint::ArrayEncoding
+ bigint::AddMod<Output = Self::Uint>
+ bigint::Encoding
+ bigint::Integer
+ bigint::NegMod<Output = Self::Uint>
+ bigint::Random
+ bigint::RandomMod
+ bigint::SubMod<Output = Self::Uint>
+ zeroize::Zeroize
+ FieldBytesEncoding<Self>
+ ShrAssign<usize>;
/// Order of this elliptic curve, i.e. number of elements in the scalar
/// field.
const ORDER: Self::Uint;
}
/// Marker trait for elliptic curves with prime order.
pub trait PrimeCurve: Curve {}

229
vendor/elliptic-curve/src/ops.rs vendored Normal file
View File

@@ -0,0 +1,229 @@
//! Traits for arithmetic operations on elliptic curve field elements.
pub use core::ops::{Add, AddAssign, Mul, Neg, Shr, ShrAssign, Sub, SubAssign};
use crypto_bigint::Integer;
use group::Group;
use subtle::{Choice, ConditionallySelectable, CtOption};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
/// Perform an inversion on a field element (i.e. base field element or scalar)
pub trait Invert {
/// Field element type
type Output;
/// Invert a field element.
fn invert(&self) -> Self::Output;
/// Invert a field element in variable time.
///
/// ⚠️ WARNING!
///
/// This method should not be used with secret values, as its variable-time
/// operation can potentially leak secrets through sidechannels.
fn invert_vartime(&self) -> Self::Output {
// Fall back on constant-time implementation by default.
self.invert()
}
}
/// Perform a batched inversion on a sequence of field elements (i.e. base field elements or scalars)
/// at an amortized cost that should be practically as efficient as a single inversion.
pub trait BatchInvert<FieldElements: ?Sized>: Invert + Sized {
/// The output of batch inversion. A container of field elements.
type Output: AsRef<[Self]>;
/// Invert a batch of field elements.
fn batch_invert(
field_elements: &FieldElements,
) -> CtOption<<Self as BatchInvert<FieldElements>>::Output>;
}
impl<const N: usize, T> BatchInvert<[T; N]> for T
where
T: Invert<Output = CtOption<Self>>
+ Mul<Self, Output = Self>
+ Copy
+ Default
+ ConditionallySelectable,
{
type Output = [Self; N];
fn batch_invert(field_elements: &[Self; N]) -> CtOption<[Self; N]> {
let mut field_elements_multiples = [Self::default(); N];
let mut field_elements_multiples_inverses = [Self::default(); N];
let mut field_elements_inverses = [Self::default(); N];
let inversion_succeeded = invert_batch_internal(
field_elements,
&mut field_elements_multiples,
&mut field_elements_multiples_inverses,
&mut field_elements_inverses,
);
CtOption::new(field_elements_inverses, inversion_succeeded)
}
}
#[cfg(feature = "alloc")]
impl<T> BatchInvert<[T]> for T
where
T: Invert<Output = CtOption<Self>>
+ Mul<Self, Output = Self>
+ Copy
+ Default
+ ConditionallySelectable,
{
type Output = Vec<Self>;
fn batch_invert(field_elements: &[Self]) -> CtOption<Vec<Self>> {
let mut field_elements_multiples: Vec<Self> = vec![Self::default(); field_elements.len()];
let mut field_elements_multiples_inverses: Vec<Self> =
vec![Self::default(); field_elements.len()];
let mut field_elements_inverses: Vec<Self> = vec![Self::default(); field_elements.len()];
let inversion_succeeded = invert_batch_internal(
field_elements,
field_elements_multiples.as_mut(),
field_elements_multiples_inverses.as_mut(),
field_elements_inverses.as_mut(),
);
CtOption::new(
field_elements_inverses.into_iter().collect(),
inversion_succeeded,
)
}
}
/// Implements "Montgomery's trick", a trick for computing many modular inverses at once.
///
/// "Montgomery's trick" works by reducing the problem of computing `n` inverses
/// to computing a single inversion, plus some storage and `O(n)` extra multiplications.
///
/// See: https://iacr.org/archive/pkc2004/29470042/29470042.pdf section 2.2.
fn invert_batch_internal<
T: Invert<Output = CtOption<T>> + Mul<T, Output = T> + Default + ConditionallySelectable,
>(
field_elements: &[T],
field_elements_multiples: &mut [T],
field_elements_multiples_inverses: &mut [T],
field_elements_inverses: &mut [T],
) -> Choice {
let batch_size = field_elements.len();
if batch_size == 0
|| batch_size != field_elements_multiples.len()
|| batch_size != field_elements_multiples_inverses.len()
{
return Choice::from(0);
}
field_elements_multiples[0] = field_elements[0];
for i in 1..batch_size {
// $ a_n = a_{n-1}*x_n $
field_elements_multiples[i] = field_elements_multiples[i - 1] * field_elements[i];
}
field_elements_multiples[batch_size - 1]
.invert()
.map(|multiple_of_inverses_of_all_field_elements| {
field_elements_multiples_inverses[batch_size - 1] =
multiple_of_inverses_of_all_field_elements;
for i in (1..batch_size).rev() {
// $ a_{n-1} = {a_n}^{-1}*x_n $
field_elements_multiples_inverses[i - 1] =
field_elements_multiples_inverses[i] * field_elements[i];
}
field_elements_inverses[0] = field_elements_multiples_inverses[0];
for i in 1..batch_size {
// $ {x_n}^{-1} = a_{n}^{-1}*a_{n-1} $
field_elements_inverses[i] =
field_elements_multiples_inverses[i] * field_elements_multiples[i - 1];
}
})
.is_some()
}
/// Linear combination.
///
/// This trait enables crates to provide an optimized implementation of
/// linear combinations (e.g. Shamir's Trick), or otherwise provides a default
/// non-optimized implementation.
// TODO(tarcieri): replace this with a trait from the `group` crate? (see zkcrypto/group#25)
pub trait LinearCombination: Group {
/// Calculates `x * k + y * l`.
fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self {
(*x * k) + (*y * l)
}
}
/// Linear combination (extended version).
///
/// This trait enables providing an optimized implementation of
/// linear combinations (e.g. Shamir's Trick).
// TODO(tarcieri): replace the current `LinearCombination` with this in the next release
pub trait LinearCombinationExt<PointsAndScalars>: group::Curve
where
PointsAndScalars: AsRef<[(Self, Self::Scalar)]> + ?Sized,
{
/// Calculates `x1 * k1 + ... + xn * kn`.
fn lincomb_ext(points_and_scalars: &PointsAndScalars) -> Self {
points_and_scalars
.as_ref()
.iter()
.copied()
.map(|(point, scalar)| point * scalar)
.sum()
}
}
/// Blanket impl of the legacy [`LinearCombination`] trait for types which impl the new
/// [`LinearCombinationExt`] trait for 2-element arrays.
impl<P: LinearCombinationExt<[(P, Self::Scalar); 2]>> LinearCombination for P {
fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self {
Self::lincomb_ext(&[(*x, *k), (*y, *l)])
}
}
/// Multiplication by the generator.
///
/// May use optimizations (e.g. precomputed tables) when available.
// TODO(tarcieri): replace this with `Group::mul_by_generator``? (see zkcrypto/group#44)
pub trait MulByGenerator: Group {
/// Multiply by the generator of the prime-order subgroup.
#[must_use]
fn mul_by_generator(scalar: &Self::Scalar) -> Self {
Self::generator() * scalar
}
}
/// Modular reduction.
pub trait Reduce<Uint: Integer>: Sized {
/// Bytes used as input to [`Reduce::reduce_bytes`].
type Bytes: AsRef<[u8]>;
/// Perform a modular reduction, returning a field element.
fn reduce(n: Uint) -> Self;
/// Interpret the given bytes as an integer and perform a modular reduction.
fn reduce_bytes(bytes: &Self::Bytes) -> Self;
}
/// Modular reduction to a non-zero output.
///
/// This trait is primarily intended for use by curve implementations such
/// as the `k256` and `p256` crates.
///
/// End users should use the [`Reduce`] impl on
/// [`NonZeroScalar`][`crate::NonZeroScalar`] instead.
pub trait ReduceNonZero<Uint: Integer>: Reduce<Uint> + Sized {
/// Perform a modular reduction, returning a field element.
fn reduce_nonzero(n: Uint) -> Self;
/// Interpret the given bytes as an integer and perform a modular reduction
/// to a non-zero output.
fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self;
}

81
vendor/elliptic-curve/src/point.rs vendored Normal file
View File

@@ -0,0 +1,81 @@
//! Traits for elliptic curve points.
#[cfg(feature = "arithmetic")]
mod non_identity;
#[cfg(feature = "arithmetic")]
pub use {self::non_identity::NonIdentity, crate::CurveArithmetic};
use crate::{Curve, FieldBytes};
use subtle::{Choice, CtOption};
/// Affine point type for a given curve with a [`CurveArithmetic`]
/// implementation.
#[cfg(feature = "arithmetic")]
pub type AffinePoint<C> = <C as CurveArithmetic>::AffinePoint;
/// Projective point type for a given curve with a [`CurveArithmetic`]
/// implementation.
#[cfg(feature = "arithmetic")]
pub type ProjectivePoint<C> = <C as CurveArithmetic>::ProjectivePoint;
/// Access to the affine coordinates of an elliptic curve point.
// TODO: use zkcrypto/group#30 coordinate API when available
pub trait AffineCoordinates {
/// Field element representation.
type FieldRepr: AsRef<[u8]>;
/// Get the affine x-coordinate as a serialized field element.
fn x(&self) -> Self::FieldRepr;
/// Is the affine y-coordinate odd?
fn y_is_odd(&self) -> Choice;
}
/// Normalize point(s) in projective representation by converting them to their affine ones.
#[cfg(feature = "arithmetic")]
pub trait BatchNormalize<Points: ?Sized>: group::Curve {
/// The output of the batch normalization; a container of affine points.
type Output: AsRef<[Self::AffineRepr]>;
/// Perform a batched conversion to affine representation on a sequence of projective points
/// at an amortized cost that should be practically as efficient as a single conversion.
/// Internally, implementors should rely upon `InvertBatch`.
fn batch_normalize(points: &Points) -> <Self as BatchNormalize<Points>>::Output;
}
/// Double a point (i.e. add it to itself)
pub trait Double {
/// Double this point.
fn double(&self) -> Self;
}
/// Decompress an elliptic curve point.
///
/// Point decompression recovers an original curve point from its x-coordinate
/// and a boolean flag indicating whether or not the y-coordinate is odd.
pub trait DecompressPoint<C: Curve>: Sized {
/// Attempt to decompress an elliptic curve point.
fn decompress(x: &FieldBytes<C>, y_is_odd: Choice) -> CtOption<Self>;
}
/// Decompact an elliptic curve point from an x-coordinate.
///
/// Decompaction relies on properties of specially-generated keys but provides
/// a more compact representation than standard point compression.
pub trait DecompactPoint<C: Curve>: Sized {
/// Attempt to decompact an elliptic curve point
fn decompact(x: &FieldBytes<C>) -> CtOption<Self>;
}
/// Point compression settings.
pub trait PointCompression {
/// Should point compression be applied by default?
const COMPRESS_POINTS: bool;
}
/// Point compaction settings.
pub trait PointCompaction {
/// Should point compaction be applied by default?
const COMPACT_POINTS: bool;
}

View File

@@ -0,0 +1,237 @@
//! Non-identity point type.
use core::ops::{Deref, Mul};
use group::{prime::PrimeCurveAffine, Curve, GroupEncoding};
use rand_core::{CryptoRng, RngCore};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
use crate::{CurveArithmetic, NonZeroScalar, Scalar};
/// Non-identity point type.
///
/// This type ensures that its value is not the identity point, ala `core::num::NonZero*`.
///
/// In the context of ECC, it's useful for ensuring that certain arithmetic
/// cannot result in the identity point.
#[derive(Clone, Copy)]
pub struct NonIdentity<P> {
point: P,
}
impl<P> NonIdentity<P>
where
P: ConditionallySelectable + ConstantTimeEq + Default,
{
/// Create a [`NonIdentity`] from a point.
pub fn new(point: P) -> CtOption<Self> {
CtOption::new(Self { point }, !point.ct_eq(&P::default()))
}
pub(crate) fn new_unchecked(point: P) -> Self {
Self { point }
}
}
impl<P> NonIdentity<P>
where
P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding,
{
/// Decode a [`NonIdentity`] from its encoding.
pub fn from_repr(repr: &P::Repr) -> CtOption<Self> {
Self::from_bytes(repr)
}
}
impl<P: Copy> NonIdentity<P> {
/// Return wrapped point.
pub fn to_point(self) -> P {
self.point
}
}
impl<P> NonIdentity<P>
where
P: ConditionallySelectable + ConstantTimeEq + Curve + Default,
{
/// Generate a random `NonIdentity<ProjectivePoint>`.
pub fn random(mut rng: impl CryptoRng + RngCore) -> Self {
loop {
if let Some(point) = Self::new(P::random(&mut rng)).into() {
break point;
}
}
}
/// Converts this element into its affine representation.
pub fn to_affine(self) -> NonIdentity<P::AffineRepr> {
NonIdentity {
point: self.point.to_affine(),
}
}
}
impl<P> NonIdentity<P>
where
P: PrimeCurveAffine,
{
/// Converts this element to its curve representation.
pub fn to_curve(self) -> NonIdentity<P::Curve> {
NonIdentity {
point: self.point.to_curve(),
}
}
}
impl<P> AsRef<P> for NonIdentity<P> {
fn as_ref(&self) -> &P {
&self.point
}
}
impl<P> ConditionallySelectable for NonIdentity<P>
where
P: ConditionallySelectable,
{
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
point: P::conditional_select(&a.point, &b.point, choice),
}
}
}
impl<P> ConstantTimeEq for NonIdentity<P>
where
P: ConstantTimeEq,
{
fn ct_eq(&self, other: &Self) -> Choice {
self.point.ct_eq(&other.point)
}
}
impl<P> Deref for NonIdentity<P> {
type Target = P;
fn deref(&self) -> &Self::Target {
&self.point
}
}
impl<P> GroupEncoding for NonIdentity<P>
where
P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding,
{
type Repr = P::Repr;
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
let point = P::from_bytes(bytes);
point.and_then(|point| CtOption::new(Self { point }, !point.ct_eq(&P::default())))
}
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
P::from_bytes_unchecked(bytes).map(|point| Self { point })
}
fn to_bytes(&self) -> Self::Repr {
self.point.to_bytes()
}
}
impl<C, P> Mul<NonZeroScalar<C>> for NonIdentity<P>
where
C: CurveArithmetic,
P: Copy + Mul<Scalar<C>, Output = P>,
{
type Output = NonIdentity<P>;
fn mul(self, rhs: NonZeroScalar<C>) -> Self::Output {
&self * &rhs
}
}
impl<C, P> Mul<&NonZeroScalar<C>> for &NonIdentity<P>
where
C: CurveArithmetic,
P: Copy + Mul<Scalar<C>, Output = P>,
{
type Output = NonIdentity<P>;
fn mul(self, rhs: &NonZeroScalar<C>) -> Self::Output {
NonIdentity {
point: self.point * *rhs.as_ref(),
}
}
}
#[cfg(feature = "serde")]
impl<P> Serialize for NonIdentity<P>
where
P: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
self.point.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, P> Deserialize<'de> for NonIdentity<P>
where
P: ConditionallySelectable + ConstantTimeEq + Default + Deserialize<'de> + GroupEncoding,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
Option::from(Self::new(P::deserialize(deserializer)?))
.ok_or_else(|| de::Error::custom("expected non-identity point"))
}
}
#[cfg(all(test, feature = "dev"))]
mod tests {
use super::NonIdentity;
use crate::dev::{AffinePoint, ProjectivePoint};
use group::GroupEncoding;
use hex_literal::hex;
#[test]
fn new_success() {
let point = ProjectivePoint::from_bytes(
&hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").into(),
)
.unwrap();
assert!(bool::from(NonIdentity::new(point).is_some()));
assert!(bool::from(
NonIdentity::new(AffinePoint::from(point)).is_some()
));
}
#[test]
fn new_fail() {
assert!(bool::from(
NonIdentity::new(ProjectivePoint::default()).is_none()
));
assert!(bool::from(
NonIdentity::new(AffinePoint::default()).is_none()
));
}
#[test]
fn round_trip() {
let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
let point = NonIdentity::<ProjectivePoint>::from_repr(&bytes.into()).unwrap();
assert_eq!(&bytes, point.to_bytes().as_slice());
let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
let point = NonIdentity::<AffinePoint>::from_repr(&bytes.into()).unwrap();
assert_eq!(&bytes, point.to_bytes().as_slice());
}
}

567
vendor/elliptic-curve/src/public_key.rs vendored Normal file
View File

@@ -0,0 +1,567 @@
//! Elliptic curve public keys.
use crate::{
point::NonIdentity, AffinePoint, CurveArithmetic, Error, NonZeroScalar, ProjectivePoint, Result,
};
use core::fmt::Debug;
use group::{Curve, Group};
#[cfg(feature = "jwk")]
use crate::{JwkEcKey, JwkParameters};
#[cfg(feature = "pkcs8")]
use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier};
#[cfg(feature = "pem")]
use core::str::FromStr;
#[cfg(feature = "sec1")]
use {
crate::{
point::PointCompression,
sec1::{CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint},
FieldBytesSize,
},
core::cmp::Ordering,
subtle::{Choice, CtOption},
};
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
use pkcs8::EncodePublicKey;
#[cfg(all(feature = "alloc", feature = "sec1"))]
use alloc::boxed::Box;
#[cfg(any(feature = "jwk", feature = "pem"))]
use alloc::string::{String, ToString};
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
#[cfg(any(feature = "pem", feature = "serde"))]
use pkcs8::DecodePublicKey;
#[cfg(all(feature = "sec1", feature = "pkcs8"))]
use {
crate::{
pkcs8::{self, AssociatedOid},
ALGORITHM_OID,
},
pkcs8::der,
};
/// Elliptic curve public keys.
///
/// This is a wrapper type for [`AffinePoint`] which ensures an inner
/// non-identity point and provides a common place to handle encoding/decoding.
///
/// # Parsing "SPKI" Keys
///
/// X.509 `SubjectPublicKeyInfo` (SPKI) is a commonly used format for encoding
/// public keys, notably public keys corresponding to PKCS#8 private keys.
/// (especially ones generated by OpenSSL).
///
/// Keys in SPKI format are either binary (ASN.1 BER/DER), or PEM encoded
/// (ASCII) and begin with the following:
///
/// ```text
/// -----BEGIN PUBLIC KEY-----
/// ```
///
/// To decode an elliptic curve public key from SPKI, enable the `pkcs8`
/// feature of this crate (or the `pkcs8` feature of a specific RustCrypto
/// elliptic curve crate) and use the
/// [`elliptic_curve::pkcs8::DecodePublicKey`][`pkcs8::DecodePublicKey`]
/// trait to parse it.
///
/// When the `pem` feature of this crate (or a specific RustCrypto elliptic
/// curve crate) is enabled, a [`FromStr`] impl is also available.
///
/// # `serde` support
///
/// When the optional `serde` feature of this create is enabled, [`Serialize`]
/// and [`Deserialize`] impls are provided for this type.
///
/// The serialization is binary-oriented and supports ASN.1 DER
/// Subject Public Key Info (SPKI) as the encoding format.
///
/// For a more text-friendly encoding of public keys, use [`JwkEcKey`] instead.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PublicKey<C>
where
C: CurveArithmetic,
{
point: AffinePoint<C>,
}
impl<C> PublicKey<C>
where
C: CurveArithmetic,
{
/// Convert an [`AffinePoint`] into a [`PublicKey`]
pub fn from_affine(point: AffinePoint<C>) -> Result<Self> {
if ProjectivePoint::<C>::from(point).is_identity().into() {
Err(Error)
} else {
Ok(Self { point })
}
}
/// Compute a [`PublicKey`] from a secret [`NonZeroScalar`] value
/// (i.e. a secret key represented as a raw scalar value)
pub fn from_secret_scalar(scalar: &NonZeroScalar<C>) -> Self {
// `NonZeroScalar` ensures the resulting point is not the identity
Self {
point: (C::ProjectivePoint::generator() * scalar.as_ref()).to_affine(),
}
}
/// Decode [`PublicKey`] (compressed or uncompressed) from the
/// `Elliptic-Curve-Point-to-Octet-String` encoding described in
/// SEC 1: Elliptic Curve Cryptography (Version 2.0) section
/// 2.3.3 (page 10).
///
/// <http://www.secg.org/sec1-v2.pdf>
#[cfg(feature = "sec1")]
pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self>
where
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
{
let point = EncodedPoint::<C>::from_bytes(bytes).map_err(|_| Error)?;
Option::from(Self::from_encoded_point(&point)).ok_or(Error)
}
/// Convert this [`PublicKey`] into the
/// `Elliptic-Curve-Point-to-Octet-String` encoding described in
/// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3
/// (page 10).
///
/// <http://www.secg.org/sec1-v2.pdf>
#[cfg(all(feature = "alloc", feature = "sec1"))]
pub fn to_sec1_bytes(&self) -> Box<[u8]>
where
C: PointCompression,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
EncodedPoint::<C>::from(self).to_bytes()
}
/// Borrow the inner [`AffinePoint`] from this [`PublicKey`].
///
/// In ECC, public keys are elliptic curve points.
pub fn as_affine(&self) -> &AffinePoint<C> {
&self.point
}
/// Convert this [`PublicKey`] to a [`ProjectivePoint`] for the given curve
pub fn to_projective(&self) -> ProjectivePoint<C> {
self.point.into()
}
/// Convert this [`PublicKey`] to a [`NonIdentity`] of the inner [`AffinePoint`]
pub fn to_nonidentity(&self) -> NonIdentity<AffinePoint<C>> {
NonIdentity::new_unchecked(self.point)
}
/// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`PublicKey`].
#[cfg(feature = "jwk")]
pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self>
where
C: JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
jwk.to_public_key::<C>()
}
/// Parse a string containing a JSON Web Key (JWK) into a [`PublicKey`].
#[cfg(feature = "jwk")]
pub fn from_jwk_str(jwk: &str) -> Result<Self>
where
C: JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
jwk.parse::<JwkEcKey>().and_then(|jwk| Self::from_jwk(&jwk))
}
/// Serialize this public key as [`JwkEcKey`] JSON Web Key (JWK).
#[cfg(feature = "jwk")]
pub fn to_jwk(&self) -> JwkEcKey
where
C: JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
self.into()
}
/// Serialize this public key as JSON Web Key (JWK) string.
#[cfg(feature = "jwk")]
pub fn to_jwk_string(&self) -> String
where
C: JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
self.to_jwk().to_string()
}
}
impl<C> AsRef<AffinePoint<C>> for PublicKey<C>
where
C: CurveArithmetic,
{
fn as_ref(&self) -> &AffinePoint<C> {
self.as_affine()
}
}
impl<C> Copy for PublicKey<C> where C: CurveArithmetic {}
#[cfg(feature = "sec1")]
impl<C> FromEncodedPoint<C> for PublicKey<C>
where
C: CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
/// Initialize [`PublicKey`] from an [`EncodedPoint`]
fn from_encoded_point(encoded_point: &EncodedPoint<C>) -> CtOption<Self> {
AffinePoint::<C>::from_encoded_point(encoded_point).and_then(|point| {
// Defeating the point of `subtle`, but the use case is specifically a public key
let is_identity = Choice::from(u8::from(encoded_point.is_identity()));
CtOption::new(PublicKey { point }, !is_identity)
})
}
}
#[cfg(feature = "sec1")]
impl<C> ToEncodedPoint<C> for PublicKey<C>
where
C: CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
/// Serialize this [`PublicKey`] as a SEC1 [`EncodedPoint`], optionally applying
/// point compression
fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
self.point.to_encoded_point(compress)
}
}
#[cfg(feature = "sec1")]
impl<C> From<PublicKey<C>> for CompressedPoint<C>
where
C: CurveArithmetic + PointCompression,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn from(public_key: PublicKey<C>) -> CompressedPoint<C> {
CompressedPoint::<C>::from(&public_key)
}
}
#[cfg(feature = "sec1")]
impl<C> From<&PublicKey<C>> for CompressedPoint<C>
where
C: CurveArithmetic + PointCompression,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn from(public_key: &PublicKey<C>) -> CompressedPoint<C> {
CompressedPoint::<C>::clone_from_slice(public_key.to_encoded_point(true).as_bytes())
}
}
#[cfg(feature = "sec1")]
impl<C> From<PublicKey<C>> for EncodedPoint<C>
where
C: CurveArithmetic + PointCompression,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn from(public_key: PublicKey<C>) -> EncodedPoint<C> {
EncodedPoint::<C>::from(&public_key)
}
}
#[cfg(feature = "sec1")]
impl<C> From<&PublicKey<C>> for EncodedPoint<C>
where
C: CurveArithmetic + PointCompression,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn from(public_key: &PublicKey<C>) -> EncodedPoint<C> {
public_key.to_encoded_point(C::COMPRESS_POINTS)
}
}
impl<C, P> From<NonIdentity<P>> for PublicKey<C>
where
C: CurveArithmetic,
P: Copy + Into<AffinePoint<C>>,
{
fn from(value: NonIdentity<P>) -> Self {
Self::from(&value)
}
}
impl<C, P> From<&NonIdentity<P>> for PublicKey<C>
where
C: CurveArithmetic,
P: Copy + Into<AffinePoint<C>>,
{
fn from(value: &NonIdentity<P>) -> Self {
Self {
point: value.to_point().into(),
}
}
}
impl<C> From<PublicKey<C>> for NonIdentity<AffinePoint<C>>
where
C: CurveArithmetic,
{
fn from(value: PublicKey<C>) -> Self {
Self::from(&value)
}
}
impl<C> From<&PublicKey<C>> for NonIdentity<AffinePoint<C>>
where
C: CurveArithmetic,
{
fn from(value: &PublicKey<C>) -> Self {
PublicKey::to_nonidentity(value)
}
}
#[cfg(feature = "sec1")]
impl<C> PartialOrd for PublicKey<C>
where
C: CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg(feature = "sec1")]
impl<C> Ord for PublicKey<C>
where
C: CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn cmp(&self, other: &Self) -> Ordering {
// TODO(tarcieri): more efficient implementation?
// This is implemented this way to reduce bounds for `AffinePoint<C>`
self.to_encoded_point(false)
.cmp(&other.to_encoded_point(false))
}
}
#[cfg(feature = "sec1")]
impl<C> TryFrom<CompressedPoint<C>> for PublicKey<C>
where
C: CurveArithmetic,
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
{
type Error = Error;
fn try_from(point: CompressedPoint<C>) -> Result<Self> {
Self::from_sec1_bytes(&point)
}
}
#[cfg(feature = "sec1")]
impl<C> TryFrom<&CompressedPoint<C>> for PublicKey<C>
where
C: CurveArithmetic,
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
{
type Error = Error;
fn try_from(point: &CompressedPoint<C>) -> Result<Self> {
Self::from_sec1_bytes(point)
}
}
#[cfg(feature = "sec1")]
impl<C> TryFrom<EncodedPoint<C>> for PublicKey<C>
where
C: CurveArithmetic,
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
{
type Error = Error;
fn try_from(point: EncodedPoint<C>) -> Result<Self> {
Self::from_sec1_bytes(point.as_bytes())
}
}
#[cfg(feature = "sec1")]
impl<C> TryFrom<&EncodedPoint<C>> for PublicKey<C>
where
C: CurveArithmetic,
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
{
type Error = Error;
fn try_from(point: &EncodedPoint<C>) -> Result<Self> {
Self::from_sec1_bytes(point.as_bytes())
}
}
#[cfg(feature = "pkcs8")]
impl<C> AssociatedAlgorithmIdentifier for PublicKey<C>
where
C: AssociatedOid + CurveArithmetic,
{
type Params = ObjectIdentifier;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = AlgorithmIdentifier {
oid: ALGORITHM_OID,
parameters: Some(C::OID),
};
}
#[cfg(feature = "pkcs8")]
impl<C> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey<C>
where
C: AssociatedOid + CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
type Error = pkcs8::spki::Error;
fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
Self::try_from(&spki)
}
}
#[cfg(feature = "pkcs8")]
impl<C> TryFrom<&pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey<C>
where
C: AssociatedOid + CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
type Error = pkcs8::spki::Error;
fn try_from(spki: &pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
spki.algorithm.assert_oids(ALGORITHM_OID, C::OID)?;
let public_key_bytes = spki
.subject_public_key
.as_bytes()
.ok_or_else(|| der::Tag::BitString.value_error())?;
Self::from_sec1_bytes(public_key_bytes)
.map_err(|_| der::Tag::BitString.value_error().into())
}
}
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
impl<C> EncodePublicKey for PublicKey<C>
where
C: AssociatedOid + CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn to_public_key_der(&self) -> pkcs8::spki::Result<der::Document> {
let public_key_bytes = self.to_encoded_point(false);
let subject_public_key = der::asn1::BitStringRef::new(0, public_key_bytes.as_bytes())?;
pkcs8::SubjectPublicKeyInfo {
algorithm: Self::ALGORITHM_IDENTIFIER,
subject_public_key,
}
.try_into()
}
}
#[cfg(feature = "pem")]
impl<C> FromStr for PublicKey<C>
where
C: AssociatedOid + CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
Self::from_public_key_pem(s).map_err(|_| Error)
}
}
#[cfg(feature = "pem")]
impl<C> ToString for PublicKey<C>
where
C: AssociatedOid + CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn to_string(&self) -> String {
self.to_public_key_pem(Default::default())
.expect("PEM encoding error")
}
}
#[cfg(feature = "serde")]
impl<C> Serialize for PublicKey<C>
where
C: AssociatedOid + CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let der = self.to_public_key_der().map_err(ser::Error::custom)?;
serdect::slice::serialize_hex_upper_or_bin(&der, serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, C> Deserialize<'de> for PublicKey<C>
where
C: AssociatedOid + CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
Self::from_public_key_der(&der_bytes).map_err(de::Error::custom)
}
}
#[cfg(all(feature = "dev", test))]
mod tests {
use crate::{dev::MockCurve, sec1::FromEncodedPoint};
type EncodedPoint = crate::sec1::EncodedPoint<MockCurve>;
type PublicKey = super::PublicKey<MockCurve>;
#[test]
fn from_encoded_point_rejects_identity() {
let identity = EncodedPoint::identity();
assert!(bool::from(
PublicKey::from_encoded_point(&identity).is_none()
));
}
}

53
vendor/elliptic-curve/src/scalar.rs vendored Normal file
View File

@@ -0,0 +1,53 @@
//! Scalar types.
#[cfg(feature = "arithmetic")]
mod blinded;
#[cfg(feature = "arithmetic")]
mod nonzero;
mod primitive;
pub use self::primitive::ScalarPrimitive;
#[cfg(feature = "arithmetic")]
pub use self::{blinded::BlindedScalar, nonzero::NonZeroScalar};
use crypto_bigint::Integer;
use subtle::Choice;
#[cfg(feature = "arithmetic")]
use crate::CurveArithmetic;
/// Scalar field element for a particular elliptic curve.
#[cfg(feature = "arithmetic")]
pub type Scalar<C> = <C as CurveArithmetic>::Scalar;
/// Bit representation of a scalar field element of a given curve.
#[cfg(feature = "bits")]
pub type ScalarBits<C> = ff::FieldBits<<Scalar<C> as ff::PrimeFieldBits>::ReprBits>;
/// Instantiate a scalar from an unsigned integer without checking for overflow.
pub trait FromUintUnchecked {
/// Unsigned integer type (i.e. `Curve::Uint`)
type Uint: Integer;
/// Instantiate scalar from an unsigned integer without checking
/// whether the value overflows the field modulus.
///
/// ⚠️ WARNING!
///
/// Incorrectly used this can lead to mathematically invalid results,
/// which can lead to potential security vulnerabilities.
///
/// Use with care!
fn from_uint_unchecked(uint: Self::Uint) -> Self;
}
/// Is this scalar greater than n / 2?
///
/// # Returns
///
/// - For scalars 0 through n / 2: `Choice::from(0)`
/// - For scalars (n / 2) + 1 through n - 1: `Choice::from(1)`
pub trait IsHigh {
/// Is this scalar greater than or equal to n / 2?
fn is_high(&self) -> Choice;
}

View File

@@ -0,0 +1,74 @@
//! Random blinding support for [`Scalar`]
use super::Scalar;
use crate::{ops::Invert, CurveArithmetic};
use group::ff::Field;
use rand_core::CryptoRngCore;
use subtle::CtOption;
use zeroize::Zeroize;
/// Scalar blinded with a randomly generated masking value.
///
/// This provides a randomly blinded impl of [`Invert`] which is useful for
/// e.g. ECDSA ephemeral (`k`) scalars.
///
/// It implements masked variable-time inversions using Stein's algorithm, which
/// may be helpful for performance on embedded platforms.
#[derive(Clone)]
pub struct BlindedScalar<C>
where
C: CurveArithmetic,
{
/// Actual scalar value.
scalar: Scalar<C>,
/// Mask value.
mask: Scalar<C>,
}
impl<C> BlindedScalar<C>
where
C: CurveArithmetic,
{
/// Create a new [`BlindedScalar`] from a scalar and a [`CryptoRngCore`].
pub fn new(scalar: Scalar<C>, rng: &mut impl CryptoRngCore) -> Self {
Self {
scalar,
mask: Scalar::<C>::random(rng),
}
}
}
impl<C> AsRef<Scalar<C>> for BlindedScalar<C>
where
C: CurveArithmetic,
{
fn as_ref(&self) -> &Scalar<C> {
&self.scalar
}
}
impl<C> Invert for BlindedScalar<C>
where
C: CurveArithmetic,
{
type Output = CtOption<Scalar<C>>;
fn invert(&self) -> CtOption<Scalar<C>> {
// prevent side channel analysis of scalar inversion by pre-and-post-multiplying
// with the random masking scalar
(self.scalar * self.mask)
.invert_vartime()
.map(|s| s * self.mask)
}
}
impl<C> Drop for BlindedScalar<C>
where
C: CurveArithmetic,
{
fn drop(&mut self) {
self.scalar.zeroize();
self.mask.zeroize();
}
}

View File

@@ -0,0 +1,405 @@
//! Non-zero scalar type.
use crate::{
ops::{Invert, Reduce, ReduceNonZero},
scalar::IsHigh,
CurveArithmetic, Error, FieldBytes, PrimeCurve, Scalar, ScalarPrimitive, SecretKey,
};
use base16ct::HexDisplay;
use core::{
fmt,
ops::{Deref, Mul, Neg},
str,
};
use crypto_bigint::{ArrayEncoding, Integer};
use ff::{Field, PrimeField};
use generic_array::{typenum::Unsigned, GenericArray};
use rand_core::CryptoRngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
use zeroize::Zeroize;
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
/// Non-zero scalar type.
///
/// This type ensures that its value is not zero, ala `core::num::NonZero*`.
/// To do this, the generic `S` type must impl both `Default` and
/// `ConstantTimeEq`, with the requirement that `S::default()` returns 0.
///
/// In the context of ECC, it's useful for ensuring that scalar multiplication
/// cannot result in the point at infinity.
#[derive(Clone)]
pub struct NonZeroScalar<C>
where
C: CurveArithmetic,
{
scalar: Scalar<C>,
}
impl<C> NonZeroScalar<C>
where
C: CurveArithmetic,
{
/// Generate a random `NonZeroScalar`.
pub fn random(mut rng: &mut impl CryptoRngCore) -> Self {
// Use rejection sampling to eliminate zero values.
// While this method isn't constant-time, the attacker shouldn't learn
// anything about unrelated outputs so long as `rng` is a secure `CryptoRng`.
loop {
if let Some(result) = Self::new(Field::random(&mut rng)).into() {
break result;
}
}
}
/// Create a [`NonZeroScalar`] from a scalar.
pub fn new(scalar: Scalar<C>) -> CtOption<Self> {
CtOption::new(Self { scalar }, !scalar.is_zero())
}
/// Decode a [`NonZeroScalar`] from a big endian-serialized field element.
pub fn from_repr(repr: FieldBytes<C>) -> CtOption<Self> {
Scalar::<C>::from_repr(repr).and_then(Self::new)
}
/// Create a [`NonZeroScalar`] from a `C::Uint`.
pub fn from_uint(uint: C::Uint) -> CtOption<Self> {
ScalarPrimitive::new(uint).and_then(|scalar| Self::new(scalar.into()))
}
}
impl<C> AsRef<Scalar<C>> for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn as_ref(&self) -> &Scalar<C> {
&self.scalar
}
}
impl<C> ConditionallySelectable for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
scalar: Scalar::<C>::conditional_select(&a.scalar, &b.scalar, choice),
}
}
}
impl<C> ConstantTimeEq for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn ct_eq(&self, other: &Self) -> Choice {
self.scalar.ct_eq(&other.scalar)
}
}
impl<C> Copy for NonZeroScalar<C> where C: CurveArithmetic {}
impl<C> Deref for NonZeroScalar<C>
where
C: CurveArithmetic,
{
type Target = Scalar<C>;
fn deref(&self) -> &Scalar<C> {
&self.scalar
}
}
impl<C> From<NonZeroScalar<C>> for FieldBytes<C>
where
C: CurveArithmetic,
{
fn from(scalar: NonZeroScalar<C>) -> FieldBytes<C> {
Self::from(&scalar)
}
}
impl<C> From<&NonZeroScalar<C>> for FieldBytes<C>
where
C: CurveArithmetic,
{
fn from(scalar: &NonZeroScalar<C>) -> FieldBytes<C> {
scalar.to_repr()
}
}
impl<C> From<NonZeroScalar<C>> for ScalarPrimitive<C>
where
C: CurveArithmetic,
{
#[inline]
fn from(scalar: NonZeroScalar<C>) -> ScalarPrimitive<C> {
Self::from(&scalar)
}
}
impl<C> From<&NonZeroScalar<C>> for ScalarPrimitive<C>
where
C: CurveArithmetic,
{
fn from(scalar: &NonZeroScalar<C>) -> ScalarPrimitive<C> {
ScalarPrimitive::from_bytes(&scalar.to_repr()).unwrap()
}
}
impl<C> From<SecretKey<C>> for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn from(sk: SecretKey<C>) -> NonZeroScalar<C> {
Self::from(&sk)
}
}
impl<C> From<&SecretKey<C>> for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn from(sk: &SecretKey<C>) -> NonZeroScalar<C> {
let scalar = sk.as_scalar_primitive().to_scalar();
debug_assert!(!bool::from(scalar.is_zero()));
Self { scalar }
}
}
impl<C> Invert for NonZeroScalar<C>
where
C: CurveArithmetic,
Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
{
type Output = Self;
fn invert(&self) -> Self {
Self {
// This will always succeed since `scalar` will never be 0
scalar: Invert::invert(&self.scalar).unwrap(),
}
}
fn invert_vartime(&self) -> Self::Output {
Self {
// This will always succeed since `scalar` will never be 0
scalar: Invert::invert_vartime(&self.scalar).unwrap(),
}
}
}
impl<C> IsHigh for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn is_high(&self) -> Choice {
self.scalar.is_high()
}
}
impl<C> Neg for NonZeroScalar<C>
where
C: CurveArithmetic,
{
type Output = NonZeroScalar<C>;
fn neg(self) -> NonZeroScalar<C> {
let scalar = -self.scalar;
debug_assert!(!bool::from(scalar.is_zero()));
NonZeroScalar { scalar }
}
}
impl<C> Mul<NonZeroScalar<C>> for NonZeroScalar<C>
where
C: PrimeCurve + CurveArithmetic,
{
type Output = Self;
#[inline]
fn mul(self, other: Self) -> Self {
Self::mul(self, &other)
}
}
impl<C> Mul<&NonZeroScalar<C>> for NonZeroScalar<C>
where
C: PrimeCurve + CurveArithmetic,
{
type Output = Self;
fn mul(self, other: &Self) -> Self {
// Multiplication is modulo a prime, so the product of two non-zero
// scalars is also non-zero.
let scalar = self.scalar * other.scalar;
debug_assert!(!bool::from(scalar.is_zero()));
NonZeroScalar { scalar }
}
}
/// Note: this is a non-zero reduction, as it's impl'd for [`NonZeroScalar`].
impl<C, I> Reduce<I> for NonZeroScalar<C>
where
C: CurveArithmetic,
I: Integer + ArrayEncoding,
Scalar<C>: Reduce<I> + ReduceNonZero<I>,
{
type Bytes = <Scalar<C> as Reduce<I>>::Bytes;
fn reduce(n: I) -> Self {
let scalar = Scalar::<C>::reduce_nonzero(n);
debug_assert!(!bool::from(scalar.is_zero()));
Self { scalar }
}
fn reduce_bytes(bytes: &Self::Bytes) -> Self {
let scalar = Scalar::<C>::reduce_nonzero_bytes(bytes);
debug_assert!(!bool::from(scalar.is_zero()));
Self { scalar }
}
}
/// Note: forwards to the [`Reduce`] impl.
impl<C, I> ReduceNonZero<I> for NonZeroScalar<C>
where
Self: Reduce<I>,
C: CurveArithmetic,
I: Integer + ArrayEncoding,
Scalar<C>: Reduce<I, Bytes = Self::Bytes> + ReduceNonZero<I>,
{
fn reduce_nonzero(n: I) -> Self {
Self::reduce(n)
}
fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self {
Self::reduce_bytes(bytes)
}
}
impl<C> TryFrom<&[u8]> for NonZeroScalar<C>
where
C: CurveArithmetic,
{
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() == C::FieldBytesSize::USIZE {
Option::from(NonZeroScalar::from_repr(GenericArray::clone_from_slice(
bytes,
)))
.ok_or(Error)
} else {
Err(Error)
}
}
}
impl<C> Zeroize for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn zeroize(&mut self) {
// Use zeroize's volatile writes to ensure value is cleared.
self.scalar.zeroize();
// Write a 1 instead of a 0 to ensure this type's non-zero invariant
// is upheld.
self.scalar = Scalar::<C>::ONE;
}
}
impl<C> fmt::Display for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:X}")
}
}
impl<C> fmt::LowerHex for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:x}", HexDisplay(&self.to_repr()))
}
}
impl<C> fmt::UpperHex for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:}", HexDisplay(&self.to_repr()))
}
}
impl<C> str::FromStr for NonZeroScalar<C>
where
C: CurveArithmetic,
{
type Err = Error;
fn from_str(hex: &str) -> Result<Self, Error> {
let mut bytes = FieldBytes::<C>::default();
if base16ct::mixed::decode(hex, &mut bytes)?.len() == bytes.len() {
Option::from(Self::from_repr(bytes)).ok_or(Error)
} else {
Err(Error)
}
}
}
#[cfg(feature = "serde")]
impl<C> Serialize for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
ScalarPrimitive::from(self).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, C> Deserialize<'de> for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
let scalar = ScalarPrimitive::deserialize(deserializer)?;
Option::from(Self::new(scalar.into()))
.ok_or_else(|| de::Error::custom("expected non-zero scalar"))
}
}
#[cfg(all(test, feature = "dev"))]
mod tests {
use crate::dev::{NonZeroScalar, Scalar};
use ff::{Field, PrimeField};
use hex_literal::hex;
use zeroize::Zeroize;
#[test]
fn round_trip() {
let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
let scalar = NonZeroScalar::from_repr(bytes.into()).unwrap();
assert_eq!(&bytes, scalar.to_repr().as_slice());
}
#[test]
fn zeroize() {
let mut scalar = NonZeroScalar::new(Scalar::from(42u64)).unwrap();
scalar.zeroize();
assert_eq!(*scalar, Scalar::ONE);
}
}

View File

@@ -0,0 +1,434 @@
//! Generic scalar type with primitive functionality.
use crate::{
bigint::{prelude::*, Limb, NonZero},
scalar::FromUintUnchecked,
scalar::IsHigh,
Curve, Error, FieldBytes, FieldBytesEncoding, Result,
};
use base16ct::HexDisplay;
use core::{
cmp::Ordering,
fmt,
ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign},
str,
};
use generic_array::{typenum::Unsigned, GenericArray};
use rand_core::CryptoRngCore;
use subtle::{
Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
CtOption,
};
use zeroize::DefaultIsZeroes;
#[cfg(feature = "arithmetic")]
use super::{CurveArithmetic, Scalar};
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
/// Generic scalar type with primitive functionality.
///
/// This type provides a baseline level of scalar arithmetic functionality
/// which is always available for all curves, regardless of if they implement
/// any arithmetic traits.
///
/// # `serde` support
///
/// When the optional `serde` feature of this create is enabled, [`Serialize`]
/// and [`Deserialize`] impls are provided for this type.
///
/// The serialization is a fixed-width big endian encoding. When used with
/// textual formats, the binary data is encoded as hexadecimal.
// TODO(tarcieri): use `crypto-bigint`'s `Residue` type, expose more functionality?
#[derive(Copy, Clone, Debug, Default)]
pub struct ScalarPrimitive<C: Curve> {
/// Inner unsigned integer type.
inner: C::Uint,
}
impl<C> ScalarPrimitive<C>
where
C: Curve,
{
/// Zero scalar.
pub const ZERO: Self = Self {
inner: C::Uint::ZERO,
};
/// Multiplicative identity.
pub const ONE: Self = Self {
inner: C::Uint::ONE,
};
/// Scalar modulus.
pub const MODULUS: C::Uint = C::ORDER;
/// Generate a random [`ScalarPrimitive`].
pub fn random(rng: &mut impl CryptoRngCore) -> Self {
Self {
inner: C::Uint::random_mod(rng, &NonZero::new(Self::MODULUS).unwrap()),
}
}
/// Create a new scalar from [`Curve::Uint`].
pub fn new(uint: C::Uint) -> CtOption<Self> {
CtOption::new(Self { inner: uint }, uint.ct_lt(&Self::MODULUS))
}
/// Decode [`ScalarPrimitive`] from a serialized field element
pub fn from_bytes(bytes: &FieldBytes<C>) -> CtOption<Self> {
Self::new(C::Uint::decode_field_bytes(bytes))
}
/// Decode [`ScalarPrimitive`] from a big endian byte slice.
pub fn from_slice(slice: &[u8]) -> Result<Self> {
if slice.len() == C::FieldBytesSize::USIZE {
Option::from(Self::from_bytes(GenericArray::from_slice(slice))).ok_or(Error)
} else {
Err(Error)
}
}
/// Borrow the inner `C::Uint`.
pub fn as_uint(&self) -> &C::Uint {
&self.inner
}
/// Borrow the inner limbs as a slice.
pub fn as_limbs(&self) -> &[Limb] {
self.inner.as_ref()
}
/// Is this [`ScalarPrimitive`] value equal to zero?
pub fn is_zero(&self) -> Choice {
self.inner.is_zero()
}
/// Is this [`ScalarPrimitive`] value even?
pub fn is_even(&self) -> Choice {
self.inner.is_even()
}
/// Is this [`ScalarPrimitive`] value odd?
pub fn is_odd(&self) -> Choice {
self.inner.is_odd()
}
/// Encode [`ScalarPrimitive`] as a serialized field element.
pub fn to_bytes(&self) -> FieldBytes<C> {
self.inner.encode_field_bytes()
}
/// Convert to a `C::Uint`.
pub fn to_uint(&self) -> C::Uint {
self.inner
}
}
impl<C> FromUintUnchecked for ScalarPrimitive<C>
where
C: Curve,
{
type Uint = C::Uint;
fn from_uint_unchecked(uint: C::Uint) -> Self {
Self { inner: uint }
}
}
#[cfg(feature = "arithmetic")]
impl<C> ScalarPrimitive<C>
where
C: CurveArithmetic,
{
/// Convert [`ScalarPrimitive`] into a given curve's scalar type.
pub(super) fn to_scalar(self) -> Scalar<C> {
Scalar::<C>::from_uint_unchecked(self.inner)
}
}
// TODO(tarcieri): better encapsulate this?
impl<C> AsRef<[Limb]> for ScalarPrimitive<C>
where
C: Curve,
{
fn as_ref(&self) -> &[Limb] {
self.as_limbs()
}
}
impl<C> ConditionallySelectable for ScalarPrimitive<C>
where
C: Curve,
{
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
inner: C::Uint::conditional_select(&a.inner, &b.inner, choice),
}
}
}
impl<C> ConstantTimeEq for ScalarPrimitive<C>
where
C: Curve,
{
fn ct_eq(&self, other: &Self) -> Choice {
self.inner.ct_eq(&other.inner)
}
}
impl<C> ConstantTimeLess for ScalarPrimitive<C>
where
C: Curve,
{
fn ct_lt(&self, other: &Self) -> Choice {
self.inner.ct_lt(&other.inner)
}
}
impl<C> ConstantTimeGreater for ScalarPrimitive<C>
where
C: Curve,
{
fn ct_gt(&self, other: &Self) -> Choice {
self.inner.ct_gt(&other.inner)
}
}
impl<C: Curve> DefaultIsZeroes for ScalarPrimitive<C> {}
impl<C: Curve> Eq for ScalarPrimitive<C> {}
impl<C> PartialEq for ScalarPrimitive<C>
where
C: Curve,
{
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl<C> PartialOrd for ScalarPrimitive<C>
where
C: Curve,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<C> Ord for ScalarPrimitive<C>
where
C: Curve,
{
fn cmp(&self, other: &Self) -> Ordering {
self.inner.cmp(&other.inner)
}
}
impl<C> From<u64> for ScalarPrimitive<C>
where
C: Curve,
{
fn from(n: u64) -> Self {
Self {
inner: C::Uint::from(n),
}
}
}
impl<C> Add<ScalarPrimitive<C>> for ScalarPrimitive<C>
where
C: Curve,
{
type Output = Self;
fn add(self, other: Self) -> Self {
self.add(&other)
}
}
impl<C> Add<&ScalarPrimitive<C>> for ScalarPrimitive<C>
where
C: Curve,
{
type Output = Self;
fn add(self, other: &Self) -> Self {
Self {
inner: self.inner.add_mod(&other.inner, &Self::MODULUS),
}
}
}
impl<C> AddAssign<ScalarPrimitive<C>> for ScalarPrimitive<C>
where
C: Curve,
{
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl<C> AddAssign<&ScalarPrimitive<C>> for ScalarPrimitive<C>
where
C: Curve,
{
fn add_assign(&mut self, other: &Self) {
*self = *self + other;
}
}
impl<C> Sub<ScalarPrimitive<C>> for ScalarPrimitive<C>
where
C: Curve,
{
type Output = Self;
fn sub(self, other: Self) -> Self {
self.sub(&other)
}
}
impl<C> Sub<&ScalarPrimitive<C>> for ScalarPrimitive<C>
where
C: Curve,
{
type Output = Self;
fn sub(self, other: &Self) -> Self {
Self {
inner: self.inner.sub_mod(&other.inner, &Self::MODULUS),
}
}
}
impl<C> SubAssign<ScalarPrimitive<C>> for ScalarPrimitive<C>
where
C: Curve,
{
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl<C> SubAssign<&ScalarPrimitive<C>> for ScalarPrimitive<C>
where
C: Curve,
{
fn sub_assign(&mut self, other: &Self) {
*self = *self - other;
}
}
impl<C> Neg for ScalarPrimitive<C>
where
C: Curve,
{
type Output = Self;
fn neg(self) -> Self {
Self {
inner: self.inner.neg_mod(&Self::MODULUS),
}
}
}
impl<C> Neg for &ScalarPrimitive<C>
where
C: Curve,
{
type Output = ScalarPrimitive<C>;
fn neg(self) -> ScalarPrimitive<C> {
-*self
}
}
impl<C> ShrAssign<usize> for ScalarPrimitive<C>
where
C: Curve,
{
fn shr_assign(&mut self, rhs: usize) {
self.inner >>= rhs;
}
}
impl<C> IsHigh for ScalarPrimitive<C>
where
C: Curve,
{
fn is_high(&self) -> Choice {
let n_2 = C::ORDER >> 1;
self.inner.ct_gt(&n_2)
}
}
impl<C> fmt::Display for ScalarPrimitive<C>
where
C: Curve,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:X}")
}
}
impl<C> fmt::LowerHex for ScalarPrimitive<C>
where
C: Curve,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:x}", HexDisplay(&self.to_bytes()))
}
}
impl<C> fmt::UpperHex for ScalarPrimitive<C>
where
C: Curve,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:X}", HexDisplay(&self.to_bytes()))
}
}
impl<C> str::FromStr for ScalarPrimitive<C>
where
C: Curve,
{
type Err = Error;
fn from_str(hex: &str) -> Result<Self> {
let mut bytes = FieldBytes::<C>::default();
base16ct::lower::decode(hex, &mut bytes)?;
Self::from_slice(&bytes)
}
}
#[cfg(feature = "serde")]
impl<C> Serialize for ScalarPrimitive<C>
where
C: Curve,
{
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, C> Deserialize<'de> for ScalarPrimitive<C>
where
C: Curve,
{
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
let mut bytes = FieldBytes::<C>::default();
serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?;
Self::from_slice(&bytes).map_err(|_| de::Error::custom("scalar out of range"))
}
}

114
vendor/elliptic-curve/src/sec1.rs vendored Normal file
View File

@@ -0,0 +1,114 @@
//! Support for SEC1 elliptic curve encoding formats.
//!
//! <https://www.secg.org/sec1-v2.pdf>
pub use sec1::point::{Coordinates, ModulusSize, Tag};
use crate::{Curve, FieldBytesSize, Result, SecretKey};
use generic_array::GenericArray;
use subtle::CtOption;
#[cfg(feature = "arithmetic")]
use crate::{AffinePoint, CurveArithmetic, Error};
/// Encoded elliptic curve point with point compression.
pub type CompressedPoint<C> = GenericArray<u8, CompressedPointSize<C>>;
/// Size of a compressed elliptic curve point.
pub type CompressedPointSize<C> = <FieldBytesSize<C> as ModulusSize>::CompressedPointSize;
/// Encoded elliptic curve point sized appropriately for a given curve.
pub type EncodedPoint<C> = sec1::point::EncodedPoint<FieldBytesSize<C>>;
/// Encoded elliptic curve point *without* point compression.
pub type UncompressedPoint<C> = GenericArray<u8, UncompressedPointSize<C>>;
/// Size of an uncompressed elliptic curve point.
pub type UncompressedPointSize<C> = <FieldBytesSize<C> as ModulusSize>::UncompressedPointSize;
/// Trait for deserializing a value from a SEC1 encoded curve point.
///
/// This is intended for use with the `AffinePoint` type for a given elliptic curve.
pub trait FromEncodedPoint<C>
where
Self: Sized,
C: Curve,
FieldBytesSize<C>: ModulusSize,
{
/// Deserialize the type this trait is impl'd on from an [`EncodedPoint`].
fn from_encoded_point(point: &EncodedPoint<C>) -> CtOption<Self>;
}
/// Trait for serializing a value to a SEC1 encoded curve point.
///
/// This is intended for use with the `AffinePoint` type for a given elliptic curve.
pub trait ToEncodedPoint<C>
where
C: Curve,
FieldBytesSize<C>: ModulusSize,
{
/// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying
/// point compression.
fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C>;
}
/// Trait for serializing a value to a SEC1 encoded curve point with compaction.
///
/// This is intended for use with the `AffinePoint` type for a given elliptic curve.
pub trait ToCompactEncodedPoint<C>
where
C: Curve,
FieldBytesSize<C>: ModulusSize,
{
/// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying
/// point compression.
fn to_compact_encoded_point(&self) -> CtOption<EncodedPoint<C>>;
}
/// Validate that the given [`EncodedPoint`] represents the encoded public key
/// value of the given secret.
///
/// Curve implementations which also impl [`CurveArithmetic`] will receive
/// a blanket default impl of this trait.
pub trait ValidatePublicKey
where
Self: Curve,
FieldBytesSize<Self>: ModulusSize,
{
/// Validate that the given [`EncodedPoint`] is a valid public key for the
/// provided secret value.
#[allow(unused_variables)]
fn validate_public_key(
secret_key: &SecretKey<Self>,
public_key: &EncodedPoint<Self>,
) -> Result<()> {
// Provide a default "always succeeds" implementation.
// This is the intended default for curve implementations which
// do not provide an arithmetic implementation, since they have no
// way to verify this.
//
// Implementations with an arithmetic impl will receive a blanket impl
// of this trait.
Ok(())
}
}
#[cfg(feature = "arithmetic")]
impl<C> ValidatePublicKey for C
where
C: CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn validate_public_key(secret_key: &SecretKey<C>, public_key: &EncodedPoint<C>) -> Result<()> {
let pk = secret_key
.public_key()
.to_encoded_point(public_key.is_compressed());
if public_key == &pk {
Ok(())
} else {
Err(Error)
}
}
}

386
vendor/elliptic-curve/src/secret_key.rs vendored Normal file
View File

@@ -0,0 +1,386 @@
//! Secret keys for elliptic curves (i.e. private scalars).
//!
//! The [`SecretKey`] type is a wrapper around a secret scalar value which is
//! designed to prevent unintentional exposure (e.g. via `Debug` or other
//! logging). It also handles zeroing the secret value out of memory securely
//! on drop.
#[cfg(all(feature = "pkcs8", feature = "sec1"))]
mod pkcs8;
use crate::{Curve, Error, FieldBytes, Result, ScalarPrimitive};
use core::fmt::{self, Debug};
use generic_array::typenum::Unsigned;
use subtle::{Choice, ConstantTimeEq};
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
#[cfg(feature = "arithmetic")]
use crate::{rand_core::CryptoRngCore, CurveArithmetic, NonZeroScalar, PublicKey};
#[cfg(feature = "jwk")]
use crate::jwk::{JwkEcKey, JwkParameters};
#[cfg(feature = "pem")]
use pem_rfc7468::{self as pem, PemLabel};
#[cfg(feature = "sec1")]
use {
crate::{
sec1::{EncodedPoint, ModulusSize, ValidatePublicKey},
FieldBytesSize,
},
sec1::der,
};
#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))]
use {
crate::{
sec1::{FromEncodedPoint, ToEncodedPoint},
AffinePoint,
},
alloc::vec::Vec,
sec1::der::Encode,
};
#[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))]
use alloc::string::String;
#[cfg(all(feature = "arithmetic", feature = "jwk"))]
use alloc::string::ToString;
#[cfg(all(doc, feature = "pkcs8"))]
use {crate::pkcs8::DecodePrivateKey, core::str::FromStr};
/// Elliptic curve secret keys.
///
/// This type wraps a secret scalar value, helping to prevent accidental
/// exposure and securely erasing the value from memory when dropped.
///
/// # Parsing PKCS#8 Keys
///
/// PKCS#8 is a commonly used format for encoding secret keys (especially ones
/// generated by OpenSSL).
///
/// Keys in PKCS#8 format are either binary (ASN.1 BER/DER), or PEM encoded
/// (ASCII) and begin with the following:
///
/// ```text
/// -----BEGIN PRIVATE KEY-----
/// ```
///
/// To decode an elliptic curve private key from PKCS#8, enable the `pkcs8`
/// feature of this crate (or the `pkcs8` feature of a specific RustCrypto
/// elliptic curve crate) and use the [`DecodePrivateKey`] trait to parse it.
///
/// When the `pem` feature of this crate (or a specific RustCrypto elliptic
/// curve crate) is enabled, a [`FromStr`] impl is also available.
#[derive(Clone)]
pub struct SecretKey<C: Curve> {
/// Scalar value
inner: ScalarPrimitive<C>,
}
impl<C> SecretKey<C>
where
C: Curve,
{
/// Minimum allowed size of an elliptic curve secret key in bytes.
///
/// This provides the equivalent of 96-bits of symmetric security.
const MIN_SIZE: usize = 24;
/// Generate a random [`SecretKey`].
#[cfg(feature = "arithmetic")]
pub fn random(rng: &mut impl CryptoRngCore) -> Self
where
C: CurveArithmetic,
{
Self {
inner: NonZeroScalar::<C>::random(rng).into(),
}
}
/// Create a new secret key from a scalar value.
pub fn new(scalar: ScalarPrimitive<C>) -> Self {
Self { inner: scalar }
}
/// Borrow the inner secret [`ScalarPrimitive`] value.
///
/// # ⚠️ Warning
///
/// This value is key material.
///
/// Please treat it with the care it deserves!
pub fn as_scalar_primitive(&self) -> &ScalarPrimitive<C> {
&self.inner
}
/// Get the secret [`NonZeroScalar`] value for this key.
///
/// # ⚠️ Warning
///
/// This value is key material.
///
/// Please treat it with the care it deserves!
#[cfg(feature = "arithmetic")]
pub fn to_nonzero_scalar(&self) -> NonZeroScalar<C>
where
C: CurveArithmetic,
{
self.into()
}
/// Get the [`PublicKey`] which corresponds to this secret key
#[cfg(feature = "arithmetic")]
pub fn public_key(&self) -> PublicKey<C>
where
C: CurveArithmetic,
{
PublicKey::from_secret_scalar(&self.to_nonzero_scalar())
}
/// Deserialize secret key from an encoded secret scalar.
pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> {
let inner: ScalarPrimitive<C> =
Option::from(ScalarPrimitive::from_bytes(bytes)).ok_or(Error)?;
if inner.is_zero().into() {
return Err(Error);
}
Ok(Self { inner })
}
/// Deserialize secret key from an encoded secret scalar passed as a byte slice.
///
/// The slice is expected to be a minimum of 24-bytes (192-byts) and at most `C::FieldBytesSize`
/// bytes in length.
///
/// Byte slices shorter than the field size are handled by zero padding the input.
pub fn from_slice(slice: &[u8]) -> Result<Self> {
if slice.len() == C::FieldBytesSize::USIZE {
Self::from_bytes(FieldBytes::<C>::from_slice(slice))
} else if (Self::MIN_SIZE..C::FieldBytesSize::USIZE).contains(&slice.len()) {
let mut bytes = Zeroizing::new(FieldBytes::<C>::default());
let offset = C::FieldBytesSize::USIZE.saturating_sub(slice.len());
bytes[offset..].copy_from_slice(slice);
Self::from_bytes(&bytes)
} else {
Err(Error)
}
}
/// Serialize raw secret scalar as a big endian integer.
pub fn to_bytes(&self) -> FieldBytes<C> {
self.inner.to_bytes()
}
/// Deserialize secret key encoded in the SEC1 ASN.1 DER `ECPrivateKey` format.
#[cfg(feature = "sec1")]
pub fn from_sec1_der(der_bytes: &[u8]) -> Result<Self>
where
C: Curve + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
sec1::EcPrivateKey::try_from(der_bytes)?
.try_into()
.map_err(|_| Error)
}
/// Serialize secret key in the SEC1 ASN.1 DER `ECPrivateKey` format.
#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))]
pub fn to_sec1_der(&self) -> der::Result<Zeroizing<Vec<u8>>>
where
C: CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
let private_key_bytes = Zeroizing::new(self.to_bytes());
let public_key_bytes = self.public_key().to_encoded_point(false);
let ec_private_key = Zeroizing::new(
sec1::EcPrivateKey {
private_key: &private_key_bytes,
parameters: None,
public_key: Some(public_key_bytes.as_bytes()),
}
.to_der()?,
);
Ok(ec_private_key)
}
/// Parse [`SecretKey`] from PEM-encoded SEC1 `ECPrivateKey` format.
///
/// PEM-encoded SEC1 keys can be identified by the leading delimiter:
///
/// ```text
/// -----BEGIN EC PRIVATE KEY-----
/// ```
#[cfg(feature = "pem")]
pub fn from_sec1_pem(s: &str) -> Result<Self>
where
C: Curve + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?;
if label != sec1::EcPrivateKey::PEM_LABEL {
return Err(Error);
}
Self::from_sec1_der(&der_bytes).map_err(|_| Error)
}
/// Serialize private key as self-zeroizing PEM-encoded SEC1 `ECPrivateKey`
/// with the given [`pem::LineEnding`].
///
/// Pass `Default::default()` to use the OS's native line endings.
#[cfg(feature = "pem")]
pub fn to_sec1_pem(&self, line_ending: pem::LineEnding) -> Result<Zeroizing<String>>
where
C: CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
self.to_sec1_der()
.ok()
.and_then(|der| {
pem::encode_string(sec1::EcPrivateKey::PEM_LABEL, line_ending, &der).ok()
})
.map(Zeroizing::new)
.ok_or(Error)
}
/// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`SecretKey`].
#[cfg(feature = "jwk")]
pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self>
where
C: JwkParameters + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
Self::try_from(jwk)
}
/// Parse a string containing a JSON Web Key (JWK) into a [`SecretKey`].
#[cfg(feature = "jwk")]
pub fn from_jwk_str(jwk: &str) -> Result<Self>
where
C: JwkParameters + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
jwk.parse::<JwkEcKey>().and_then(|jwk| Self::from_jwk(&jwk))
}
/// Serialize this secret key as [`JwkEcKey`] JSON Web Key (JWK).
#[cfg(all(feature = "arithmetic", feature = "jwk"))]
pub fn to_jwk(&self) -> JwkEcKey
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
self.into()
}
/// Serialize this secret key as JSON Web Key (JWK) string.
#[cfg(all(feature = "arithmetic", feature = "jwk"))]
pub fn to_jwk_string(&self) -> Zeroizing<String>
where
C: CurveArithmetic + JwkParameters,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
Zeroizing::new(self.to_jwk().to_string())
}
}
impl<C> ConstantTimeEq for SecretKey<C>
where
C: Curve,
{
fn ct_eq(&self, other: &Self) -> Choice {
self.inner.ct_eq(&other.inner)
}
}
impl<C> Debug for SecretKey<C>
where
C: Curve,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct(core::any::type_name::<Self>())
.finish_non_exhaustive()
}
}
impl<C> ZeroizeOnDrop for SecretKey<C> where C: Curve {}
impl<C> Drop for SecretKey<C>
where
C: Curve,
{
fn drop(&mut self) {
self.inner.zeroize();
}
}
impl<C: Curve> Eq for SecretKey<C> {}
impl<C> PartialEq for SecretKey<C>
where
C: Curve,
{
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
#[cfg(feature = "sec1")]
impl<C> TryFrom<sec1::EcPrivateKey<'_>> for SecretKey<C>
where
C: Curve + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
type Error = der::Error;
fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result<Self> {
let secret_key = Self::from_slice(sec1_private_key.private_key)
.map_err(|_| der::Tag::Sequence.value_error())?;
// TODO(tarcieri): validate `sec1_private_key.params`?
if let Some(pk_bytes) = sec1_private_key.public_key {
let pk = EncodedPoint::<C>::from_bytes(pk_bytes)
.map_err(|_| der::Tag::BitString.value_error())?;
if C::validate_public_key(&secret_key, &pk).is_err() {
return Err(der::Tag::BitString.value_error());
}
}
Ok(secret_key)
}
}
#[cfg(feature = "arithmetic")]
impl<C> From<NonZeroScalar<C>> for SecretKey<C>
where
C: CurveArithmetic,
{
fn from(scalar: NonZeroScalar<C>) -> SecretKey<C> {
SecretKey::from(&scalar)
}
}
#[cfg(feature = "arithmetic")]
impl<C> From<&NonZeroScalar<C>> for SecretKey<C>
where
C: CurveArithmetic,
{
fn from(scalar: &NonZeroScalar<C>) -> SecretKey<C> {
SecretKey {
inner: scalar.into(),
}
}
}

View File

@@ -0,0 +1,90 @@
//! PKCS#8 encoding/decoding support.
use super::SecretKey;
use crate::{
pkcs8::{self, der::Decode, AssociatedOid},
sec1::{ModulusSize, ValidatePublicKey},
Curve, FieldBytesSize, ALGORITHM_OID,
};
use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier};
use sec1::EcPrivateKey;
// Imports for the `EncodePrivateKey` impl
#[cfg(all(feature = "alloc", feature = "arithmetic"))]
use {
crate::{
sec1::{FromEncodedPoint, ToEncodedPoint},
AffinePoint, CurveArithmetic,
},
pkcs8::{der, EncodePrivateKey},
};
// Imports for actual PEM support
#[cfg(feature = "pem")]
use {
crate::{error::Error, Result},
core::str::FromStr,
pkcs8::DecodePrivateKey,
};
impl<C> AssociatedAlgorithmIdentifier for SecretKey<C>
where
C: AssociatedOid + Curve,
{
type Params = ObjectIdentifier;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = AlgorithmIdentifier {
oid: ALGORITHM_OID,
parameters: Some(C::OID),
};
}
impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SecretKey<C>
where
C: AssociatedOid + Curve + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
type Error = pkcs8::Error;
fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
private_key_info
.algorithm
.assert_oids(ALGORITHM_OID, C::OID)?;
let ec_private_key = EcPrivateKey::from_der(private_key_info.private_key)?;
Ok(Self::try_from(ec_private_key)?)
}
}
#[cfg(all(feature = "alloc", feature = "arithmetic"))]
impl<C> EncodePrivateKey for SecretKey<C>
where
C: AssociatedOid + CurveArithmetic,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: ModulusSize,
{
fn to_pkcs8_der(&self) -> pkcs8::Result<der::SecretDocument> {
// TODO(tarcieri): make `PrivateKeyInfo` generic around `Params`
let algorithm_identifier = pkcs8::AlgorithmIdentifierRef {
oid: ALGORITHM_OID,
parameters: Some((&C::OID).into()),
};
let ec_private_key = self.to_sec1_der()?;
let pkcs8_key = pkcs8::PrivateKeyInfo::new(algorithm_identifier, &ec_private_key);
Ok(der::SecretDocument::encode_msg(&pkcs8_key)?)
}
}
#[cfg(feature = "pem")]
impl<C> FromStr for SecretKey<C>
where
C: Curve + AssociatedOid + ValidatePublicKey,
FieldBytesSize<C>: ModulusSize,
{
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
Self::from_pkcs8_pem(s).map_err(|_| Error)
}
}

20
vendor/elliptic-curve/src/voprf.rs vendored Normal file
View File

@@ -0,0 +1,20 @@
//! Verifiable Oblivious Pseudorandom Function (VOPRF) using prime order groups
//!
//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
use crate::PrimeCurve;
/// Elliptic curve parameters used by VOPRF.
pub trait VoprfParameters: PrimeCurve {
/// The `ID` parameter which identifies a particular elliptic curve
/// as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf].
///
/// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2
const ID: &'static str;
/// The `Hash` parameter which assigns a particular hash function to this
/// ciphersuite as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf].
///
/// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2
type Hash: digest::Digest;
}

128
vendor/elliptic-curve/src/weierstrass.rs vendored Normal file
View File

@@ -0,0 +1,128 @@
//! Complete projective formulas for prime order elliptic curves as described
//! in [Renes-Costello-Batina 2015].
//!
//! [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
#![allow(clippy::op_ref)]
use ff::Field;
/// Affine point whose coordinates are represented by the given field element.
pub type AffinePoint<Fe> = (Fe, Fe);
/// Projective point whose coordinates are represented by the given field element.
pub type ProjectivePoint<Fe> = (Fe, Fe, Fe);
/// Implements the complete addition formula from [Renes-Costello-Batina 2015]
/// (Algorithm 4).
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
#[inline(always)]
pub fn add<Fe>(
(ax, ay, az): ProjectivePoint<Fe>,
(bx, by, bz): ProjectivePoint<Fe>,
curve_equation_b: Fe,
) -> ProjectivePoint<Fe>
where
Fe: Field,
{
// The comments after each line indicate which algorithm steps are being
// performed.
let xx = ax * bx; // 1
let yy = ay * by; // 2
let zz = az * bz; // 3
let xy_pairs = ((ax + ay) * &(bx + by)) - &(xx + &yy); // 4, 5, 6, 7, 8
let yz_pairs = ((ay + az) * &(by + bz)) - &(yy + &zz); // 9, 10, 11, 12, 13
let xz_pairs = ((ax + az) * &(bx + bz)) - &(xx + &zz); // 14, 15, 16, 17, 18
let bzz_part = xz_pairs - &(curve_equation_b * &zz); // 19, 20
let bzz3_part = bzz_part.double() + &bzz_part; // 21, 22
let yy_m_bzz3 = yy - &bzz3_part; // 23
let yy_p_bzz3 = yy + &bzz3_part; // 24
let zz3 = zz.double() + &zz; // 26, 27
let bxz_part = (curve_equation_b * &xz_pairs) - &(zz3 + &xx); // 25, 28, 29
let bxz3_part = bxz_part.double() + &bxz_part; // 30, 31
let xx3_m_zz3 = xx.double() + &xx - &zz3; // 32, 33, 34
(
(yy_p_bzz3 * &xy_pairs) - &(yz_pairs * &bxz3_part), // 35, 39, 40
(yy_p_bzz3 * &yy_m_bzz3) + &(xx3_m_zz3 * &bxz3_part), // 36, 37, 38
(yy_m_bzz3 * &yz_pairs) + &(xy_pairs * &xx3_m_zz3), // 41, 42, 43
)
}
/// Implements the complete mixed addition formula from
/// [Renes-Costello-Batina 2015] (Algorithm 5).
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
#[inline(always)]
pub fn add_mixed<Fe>(
(ax, ay, az): ProjectivePoint<Fe>,
(bx, by): AffinePoint<Fe>,
curve_equation_b: Fe,
) -> ProjectivePoint<Fe>
where
Fe: Field,
{
// The comments after each line indicate which algorithm steps are being
// performed.
let xx = ax * &bx; // 1
let yy = ay * &by; // 2
let xy_pairs = ((ax + &ay) * &(bx + &by)) - &(xx + &yy); // 3, 4, 5, 6, 7
let yz_pairs = (by * &az) + &ay; // 8, 9 (t4)
let xz_pairs = (bx * &az) + &ax; // 10, 11 (y3)
let bz_part = xz_pairs - &(curve_equation_b * &az); // 12, 13
let bz3_part = bz_part.double() + &bz_part; // 14, 15
let yy_m_bzz3 = yy - &bz3_part; // 16
let yy_p_bzz3 = yy + &bz3_part; // 17
let z3 = az.double() + &az; // 19, 20
let bxz_part = (curve_equation_b * &xz_pairs) - &(z3 + &xx); // 18, 21, 22
let bxz3_part = bxz_part.double() + &bxz_part; // 23, 24
let xx3_m_zz3 = xx.double() + &xx - &z3; // 25, 26, 27
(
(yy_p_bzz3 * &xy_pairs) - &(yz_pairs * &bxz3_part), // 28, 32, 33
(yy_p_bzz3 * &yy_m_bzz3) + &(xx3_m_zz3 * &bxz3_part), // 29, 30, 31
(yy_m_bzz3 * &yz_pairs) + &(xy_pairs * &xx3_m_zz3), // 34, 35, 36
)
}
/// Implements the exception-free point doubling formula from
/// [Renes-Costello-Batina 2015] (Algorithm 6).
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
#[inline(always)]
pub fn double<Fe>((x, y, z): ProjectivePoint<Fe>, curve_equation_b: Fe) -> ProjectivePoint<Fe>
where
Fe: Field,
{
// The comments after each line indicate which algorithm steps are being
// performed.
let xx = x.square(); // 1
let yy = y.square(); // 2
let zz = z.square(); // 3
let xy2 = (x * &y).double(); // 4, 5
let xz2 = (x * &z).double(); // 6, 7
let bzz_part = (curve_equation_b * &zz) - &xz2; // 8, 9
let bzz3_part = bzz_part.double() + &bzz_part; // 10, 11
let yy_m_bzz3 = yy - &bzz3_part; // 12
let yy_p_bzz3 = yy + &bzz3_part; // 13
let y_frag = yy_p_bzz3 * &yy_m_bzz3; // 14
let x_frag = yy_m_bzz3 * &xy2; // 15
let zz3 = zz.double() + &zz; // 16, 17
let bxz2_part = (curve_equation_b * &xz2) - &(zz3 + &xx); // 18, 19, 20
let bxz6_part = bxz2_part.double() + &bxz2_part; // 21, 22
let xx3_m_zz3 = xx.double() + &xx - &zz3; // 23, 24, 25
let dy = y_frag + &(xx3_m_zz3 * &bxz6_part); // 26, 27
let yz2 = (y * &z).double(); // 28, 29
let dx = x_frag - &(bxz6_part * &yz2); // 30, 31
let dz = (yz2 * &yy).double().double(); // 32, 33, 34
(dx, dy, dz)
}