From eb276c5eadae5d5f78fc165929106979fae5a944 Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Fri, 10 May 2024 17:13:38 +0300 Subject: [PATCH 01/12] Add pkcs8 module and move dsa to ecdsa --- Cargo.lock | 5 +- Cargo.toml | 4 + bign256/Cargo.toml | 14 +- bign256/src/arithmetic/scalar.rs | 2 +- bign256/src/ecdh.rs | 47 ++++++ bign256/src/{dsa.rs => ecdsa.rs} | 8 +- bign256/src/{dsa => ecdsa}/signing.rs | 0 bign256/src/{dsa => ecdsa}/verifying.rs | 29 ++-- bign256/src/lib.rs | 64 ++++---- bign256/src/public_key.rs | 190 +++++++++++++++++++++++ bign256/src/secret_key.rs | 158 +++++++++++++++++++ bign256/tests/dsa.rs | 21 +-- bign256/tests/ecdh.rs | 29 ++++ bign256/tests/examples/pkcs8-private.der | Bin 0 -> 65 bytes bign256/tests/examples/pkcs8-private.pem | 4 + bign256/tests/examples/pkcs8-public.der | Bin 0 -> 95 bytes bign256/tests/examples/pkcs8-public.pem | 4 + bign256/tests/pkcs8.rs | 86 ++++++++++ 18 files changed, 599 insertions(+), 66 deletions(-) create mode 100644 bign256/src/ecdh.rs rename bign256/src/{dsa.rs => ecdsa.rs} (95%) rename bign256/src/{dsa => ecdsa}/signing.rs (100%) rename bign256/src/{dsa => ecdsa}/verifying.rs (88%) create mode 100644 bign256/src/public_key.rs create mode 100644 bign256/src/secret_key.rs create mode 100644 bign256/tests/ecdh.rs create mode 100644 bign256/tests/examples/pkcs8-private.der create mode 100644 bign256/tests/examples/pkcs8-private.pem create mode 100644 bign256/tests/examples/pkcs8-public.der create mode 100644 bign256/tests/examples/pkcs8-public.pem create mode 100644 bign256/tests/pkcs8.rs diff --git a/Cargo.lock b/Cargo.lock index 2e2bc8af..9c045f4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,13 +54,16 @@ version = "0.14.0-pre" dependencies = [ "belt-hash", "criterion", + "der", "elliptic-curve", "hex", "hex-literal", + "pkcs8", "primeorder", "proptest", "rand_core", "rfc6979", + "sec1", "signature", ] @@ -218,8 +221,6 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "const-oid" version = "0.10.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e3352a27098ba6b09546e5f13b15165e6a88b5c2723afecb3ea9576b27e3ea" [[package]] name = "cpufeatures" diff --git a/Cargo.toml b/Cargo.toml index 126bda12..0845a36c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,7 @@ members = [ [profile.dev] opt-level = 2 + +[patch.crates-io] +#pkcs8 = { path = "/Users/makavity/dev/crypto/formats/pkcs8" } +const-oid = { path = "/Users/makavity/dev/crypto/formats/const-oid"} \ No newline at end of file diff --git a/bign256/Cargo.toml b/bign256/Cargo.toml index 23350900..12076348 100644 --- a/bign256/Cargo.toml +++ b/bign256/Cargo.toml @@ -24,22 +24,28 @@ primeorder = { version = "=0.14.0-pre.0", optional = true, path = "../primeorder signature = { version = "=2.3.0-pre.3", optional = true } belt-hash = { version = "=0.2.0-pre.3", optional = true, default-features = false } rfc6979 = { version = "=0.5.0-pre.3", optional = true } +rand_core = "0.6.4" +pkcs8 = { version = "0.11.0-pre.0", optional = true } +sec1 = { version = "0.8.0-pre.1", optional = true } +der = { version = "0.8.0-pre.0" } [dev-dependencies] criterion = "0.5" hex-literal = "0.4" proptest = "1" rand_core = { version = "0.6", features = ["getrandom"] } -hex = {version = "0.4" } +hex = { version = "0.4" } [features] -default = ["arithmetic", "pkcs8", "std", "dsa"] +default = ["arithmetic", "pkcs8", "std", "ecdsa", "pem"] alloc = ["elliptic-curve/alloc", "primeorder?/alloc"] std = ["alloc", "elliptic-curve/std", "signature?/std"] -dsa = ["arithmetic", "dep:rfc6979", "dep:signature", "dep:belt-hash"] +ecdsa = ["arithmetic", "dep:rfc6979", "dep:signature", "dep:belt-hash"] arithmetic = ["dep:primeorder", "elliptic-curve/arithmetic"] -pkcs8 = ["elliptic-curve/pkcs8"] +pem = ["pkcs8", "sec1/pem"] +pkcs8 = ["dep:pkcs8"] +ecdh = ["arithmetic", "elliptic-curve/ecdh"] [[bench]] name = "field" diff --git a/bign256/src/arithmetic/scalar.rs b/bign256/src/arithmetic/scalar.rs index 340f5169..2fecc778 100644 --- a/bign256/src/arithmetic/scalar.rs +++ b/bign256/src/arithmetic/scalar.rs @@ -15,7 +15,7 @@ mod scalar_impl; use self::scalar_impl::*; -use crate::{BignP256, FieldBytes, FieldBytesEncoding, SecretKey, ORDER_HEX, U256}; +use crate::{BignP256, FieldBytes, FieldBytesEncoding, ORDER_HEX, SecretKey, U256}; use core::{ iter::{Product, Sum}, ops::{AddAssign, MulAssign, Neg, Shr, ShrAssign, SubAssign}, diff --git a/bign256/src/ecdh.rs b/bign256/src/ecdh.rs new file mode 100644 index 00000000..bbe3681d --- /dev/null +++ b/bign256/src/ecdh.rs @@ -0,0 +1,47 @@ +//! Elliptic Curve Diffie-Hellman (Ephemeral) Support. +//! +//! This module contains a high-level interface for performing ephemeral +//! Diffie-Hellman key exchanges using the bign256 elliptic curve. +//! +//! # Usage +//! +//! This usage example is from the perspective of two participants in the +//! exchange, nicknamed "Alice" and "Bob". +//! +//! ``` +//! use bign256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; +//! use rand_core::OsRng; // requires 'getrandom' feature +//! +//! // Alice +//! let alice_secret = EphemeralSecret::random(&mut OsRng); +//! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); +//! +//! // Bob +//! let bob_secret = EphemeralSecret::random(&mut OsRng); +//! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); +//! +//! // Alice decodes Bob's serialized public key and computes a shared secret from it +//! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) +//! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! +//! +//! let alice_shared = alice_secret.diffie_hellman(&bob_public); +//! +//! // Bob decodes Alice's serialized public key and computes the same shared secret +//! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) +//! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! +//! +//! let bob_shared = bob_secret.diffie_hellman(&alice_public); +//! +//! // Both participants arrive on the same shared secret +//! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); +//! ``` + +pub use elliptic_curve::ecdh::diffie_hellman; + +use crate::BignP256; + +/// NIST P-256 Ephemeral Diffie-Hellman Secret. +pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; + +/// Shared secret value computed via ECDH key agreement. +pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; diff --git a/bign256/src/dsa.rs b/bign256/src/ecdsa.rs similarity index 95% rename from bign256/src/dsa.rs rename to bign256/src/ecdsa.rs index ffd084a7..5197eaf0 100644 --- a/bign256/src/dsa.rs +++ b/bign256/src/ecdsa.rs @@ -9,21 +9,21 @@ //! # fn example() -> Result<(), Box> { //! use rand_core::OsRng; // requires 'getrandom` feature //! use bign256::{ -//! dsa::{Signature, SigningKey, signature::Signer}, +//! ecdsa::{Signature, SigningKey, signature::Signer}, //! SecretKey //! }; //! //! // Signing //! let secret_key = SecretKey::random(&mut OsRng); // serialize with `::to_bytes()` //! let signing_key = SigningKey::new(&secret_key)?; -//! let verifying_key_bytes = signing_key.verifying_key().to_sec1_bytes(); +//! let verifying_key_bytes = signing_key.verifying_key().to_bytes(); //! let message = b"test message"; //! let signature: Signature = signing_key.sign(message); //! //! // Verifying -//! use bign256::dsa::{VerifyingKey, signature::Verifier}; +//! use bign256::ecdsa::{VerifyingKey, signature::Verifier}; //! -//! let verifying_key = VerifyingKey::from_sec1_bytes(&verifying_key_bytes)?; +//! let verifying_key = VerifyingKey::from_bytes(&verifying_key_bytes)?; //! verifying_key.verify(message, &signature)?; //! # Ok(()) //! # } diff --git a/bign256/src/dsa/signing.rs b/bign256/src/ecdsa/signing.rs similarity index 100% rename from bign256/src/dsa/signing.rs rename to bign256/src/ecdsa/signing.rs diff --git a/bign256/src/dsa/verifying.rs b/bign256/src/ecdsa/verifying.rs similarity index 88% rename from bign256/src/dsa/verifying.rs rename to bign256/src/ecdsa/verifying.rs index 64ce212f..54438f8f 100644 --- a/bign256/src/dsa/verifying.rs +++ b/bign256/src/ecdsa/verifying.rs @@ -15,9 +15,7 @@ //! ``` use super::{Signature, BELT_OID}; -use crate::{ - AffinePoint, BignP256, EncodedPoint, FieldBytes, Hash, ProjectivePoint, PublicKey, Scalar, -}; +use crate::{AffinePoint, BignP256, EncodedPoint, FieldBytes, Hash, ProjectivePoint, PublicKey, Scalar}; use belt_hash::{ digest::{Digest, FixedOutput}, BeltHash, @@ -26,13 +24,11 @@ use elliptic_curve::{ array::{consts::U32, typenum::Unsigned, Array}, group::GroupEncoding, ops::{LinearCombination, Reduce}, - sec1::ToEncodedPoint, Curve, Field, Group, }; use signature::{hazmat::PrehashVerifier, Error, Result, Verifier}; -#[cfg(feature = "alloc")] -use alloc::boxed::Box; +use elliptic_curve::sec1::ToEncodedPoint; /// Bign256 public key used for verifying signatures are valid for a given /// message. @@ -88,22 +84,17 @@ impl VerifyingKey { hasher.update(msg); hasher.finalize_fixed() } - - /// Initialize [`VerifyingKey`] from a SEC1-encoded public key. - pub fn from_sec1_bytes(bytes: &[u8]) -> Result { - let public_key = PublicKey::from_sec1_bytes(bytes).map_err(|_| Error::new())?; + + /// Parse a [`VerifyingKey`] from a byte slice. + pub fn from_bytes(bytes: &[u8]) -> Result { + let public_key = PublicKey::from_bytes(bytes).map_err(|_| Error::new())?; Self::new(public_key) } - - /// Convert this [`VerifyingKey`] 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). - /// - /// + + /// Serialize the [`VerifyingKey`] as a byte array. #[cfg(feature = "alloc")] - pub fn to_sec1_bytes(&self) -> Box<[u8]> { - self.public_key.to_sec1_bytes() + pub fn to_bytes(&self) -> Box<[u8]> { + self.public_key.to_bytes() } } diff --git a/bign256/src/lib.rs b/bign256/src/lib.rs index 2f6c5862..036459ff 100644 --- a/bign256/src/lib.rs +++ b/bign256/src/lib.rs @@ -1,5 +1,5 @@ // #![no_std] -#![no_std] +// #![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( @@ -27,34 +27,37 @@ )] #[cfg(feature = "alloc")] -#[allow(unused_extern_crates)] extern crate alloc; +pub use elliptic_curve::{self, bigint::U256}; +use elliptic_curve::{bigint::ArrayEncoding, consts::U32, Error, FieldBytesEncoding}; + +#[cfg(feature = "arithmetic")] +pub use arithmetic::{AffinePoint, ProjectivePoint, scalar::Scalar}; + +/// Bign256 result type +pub type Result = core::result::Result; + #[cfg(feature = "arithmetic")] pub mod arithmetic; #[cfg(any(feature = "test-vectors", test))] pub mod test_vectors; -#[cfg(feature = "dsa")] -pub mod dsa; - -pub use elliptic_curve::{self, bigint::U256}; - +#[cfg(feature = "ecdsa")] +pub mod ecdsa; +#[cfg(feature = "ecdh")] +pub mod ecdh; #[cfg(feature = "arithmetic")] -pub use arithmetic::{scalar::Scalar, AffinePoint, ProjectivePoint}; +pub mod public_key; +#[cfg(feature = "arithmetic")] +pub mod secret_key; #[cfg(feature = "pkcs8")] -pub use elliptic_curve::pkcs8; - -use elliptic_curve::{ - array::Array, - bigint::ArrayEncoding, - consts::{U32, U33}, - FieldBytesEncoding, -}; +const ALGORITHM_OID: pkcs8::ObjectIdentifier = + pkcs8::ObjectIdentifier::new_unwrap("1.2.112.0.2.0.34.101.45.2.1"); -#[cfg(feature = "dsa")] +#[cfg(feature = "ecdsa")] type Hash = belt_hash::digest::Output; /// Order of BIGN P-256's elliptic curve group (i.e. scalar modulus) in hexadecimal. @@ -103,12 +106,9 @@ impl elliptic_curve::point::PointCompaction for BignP256 { #[cfg(feature = "pkcs8")] impl pkcs8::AssociatedOid for BignP256 { const OID: pkcs8::ObjectIdentifier = - pkcs8::ObjectIdentifier::new_unwrap("1.2.112.0.2.0.34.101.45.1"); + pkcs8::ObjectIdentifier::new_unwrap("1.2.112.0.2.0.34.101.45.3.1"); } -/// Compressed SEC1-encoded BIGN P256 curve point. -pub type CompressedPoint = Array; - /// BIGN P-256 field element serialized as bytes. /// /// Byte array containing a serialized field element value (base field or scalar). @@ -132,14 +132,26 @@ impl FieldBytesEncoding for U256 { pub type NonZeroScalar = elliptic_curve::NonZeroScalar; /// BIGN P-256 public key. +// #[cfg(feature = "arithmetic")] +// pub type PublicKey = elliptic_curve::PublicKey; + +/// Generic scalar type with primitive functionality.# #[cfg(feature = "arithmetic")] -pub type PublicKey = elliptic_curve::PublicKey; +pub type ScalarPrimitive = elliptic_curve::ScalarPrimitive; -/// BIGN P-256 secret key. -pub type SecretKey = elliptic_curve::SecretKey; +/// Elliptic curve BignP256 public key. +#[cfg(feature = "arithmetic")] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PublicKey { + point: elliptic_curve::AffinePoint, +} -#[cfg(not(feature = "arithmetic"))] -impl elliptic_curve::sec1::ValidatePublicKey for BignP256 {} +/// Elliptic curve BignP256 Secret Key +#[cfg(feature = "arithmetic")] +#[derive(Copy, Clone, Debug)] +pub struct SecretKey { + inner: ScalarPrimitive, +} /// Bit representation of a BIGN P-256 scalar field element. #[cfg(feature = "bits")] diff --git a/bign256/src/public_key.rs b/bign256/src/public_key.rs new file mode 100644 index 00000000..f0c6eba4 --- /dev/null +++ b/bign256/src/public_key.rs @@ -0,0 +1,190 @@ +//! Public key types and traits + +use core::fmt::Display; +use core::str::FromStr; + +use elliptic_curve::{ + AffinePoint, + CurveArithmetic, + Error, + Group, + array::Array, + point::NonIdentity, + sec1::{FromEncodedPoint, ToEncodedPoint} +}; +use pkcs8::{ + AssociatedOid, + DecodePublicKey, + EncodePublicKey, + ObjectIdentifier, + spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier} +}; + +use crate::{ALGORITHM_OID, BignP256, EncodedPoint, NonZeroScalar, ProjectivePoint, PublicKey}; +impl PublicKey { + /// Convert an [`AffinePoint`] into a [`PublicKey`] + pub fn from_affine(point: AffinePoint) -> Result { + if ProjectivePoint::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) -> Self { + // `NonZeroScalar` ensures the resulting point is not the identity + #[allow(clippy::arithmetic_side_effects)] + Self { + point: (::ProjectivePoint::generator() * scalar.as_ref()) + .to_affine(), + } + } + + /// Borrow the inner [`AffinePoint`] from this [`PublicKey`]. + /// + /// In ECC, public keys are elliptic curve points. + pub fn as_affine(&self) -> &AffinePoint { + &self.point + } + + /// Convert this [`PublicKey`] to a [`ProjectivePoint`] for the given curve + pub fn to_projective(&self) -> ProjectivePoint { + self.point.into() + } + + /// Convert this [`PublicKey`] to a [`NonIdentity`] of the inner [`AffinePoint`] + pub fn to_nonidentity(&self) -> NonIdentity> { + NonIdentity::new(self.point).unwrap() + } + + /// Get [`PublicKey`] from bytes + pub fn from_bytes(bytes: &[u8]) -> Result { + let mut bytes = Array::clone_from_slice(bytes); + // It is because public_key in little endian + bytes[..32].reverse(); + bytes[32..].reverse(); + + let point = EncodedPoint::from_untagged_bytes(&bytes); + let affine = AffinePoint::::from_encoded_point(&point); + if affine.is_none().into() { + Err(Error) + } + else { + Ok(Self { point: affine.unwrap() }) + } + } + + #[cfg(feature = "alloc")] + /// Get bytes from [`PublicKey`] + pub fn to_bytes(&self) -> Box<[u8]> { + let mut bytes = self.point.to_encoded_point(false).to_bytes(); + bytes[1..32 + 1].reverse(); + bytes[33..].reverse(); + bytes[1..].to_vec().into_boxed_slice() + } +} + +impl AsRef> for PublicKey { + fn as_ref(&self) -> &AffinePoint { + self.as_affine() + } +} +impl Copy for PublicKey {} +impl From>> for PublicKey { + fn from(value: NonIdentity>) -> Self { + Self::from(&value) + } +} + +impl From<&NonIdentity>> for PublicKey { + fn from(value: &NonIdentity>) -> Self { + Self { + point: value.to_point(), + } + } +} + +impl From for NonIdentity> { + fn from(value: PublicKey) -> Self { + Self::from(&value) + } +} + +impl From<&PublicKey> for NonIdentity> { + fn from(value: &PublicKey) -> Self { + PublicKey::to_nonidentity(value) + } +} + +#[cfg(feature = "pkcs8")] +impl AssociatedAlgorithmIdentifier for PublicKey { + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some(BignP256::OID), + }; +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for PublicKey { + type Error = pkcs8::spki::Error; + + fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { + Self::try_from(&spki) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom<&pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey { + type Error = pkcs8::spki::Error; + + fn try_from(spki: &pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { + spki.algorithm.assert_oids(ALGORITHM_OID, BignP256::OID)?; + + let public_key_bytes = spki + .subject_public_key + .as_bytes() + .ok_or_else(|| der::Tag::BitString.value_error())?; + + Self::from_bytes(public_key_bytes).map_err(|_| pkcs8::spki::Error::KeyMalformed) + } +} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl EncodePublicKey for PublicKey { + fn to_public_key_der(&self) -> pkcs8::spki::Result { + let pk_bytes = self.to_bytes(); + let subject_public_key = der::asn1::BitStringRef::new(0, &pk_bytes)?; + + pkcs8::SubjectPublicKeyInfo { + algorithm: Self::ALGORITHM_IDENTIFIER, + subject_public_key, + } + .try_into() + } +} + +#[cfg(feature = "pem")] +impl FromStr for PublicKey { + type Err = Error; + + fn from_str(s: &str) -> Result { + Self::from_public_key_pem(s).map_err(|_| Error) + } +} + +#[cfg(feature = "pem")] +impl Display for PublicKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + self.to_public_key_pem(Default::default()) + .expect("PEM encoding error") + ) + } +} + diff --git a/bign256/src/secret_key.rs b/bign256/src/secret_key.rs new file mode 100644 index 00000000..9390d1f6 --- /dev/null +++ b/bign256/src/secret_key.rs @@ -0,0 +1,158 @@ +//! Bign256 secret key. + +use core::str::FromStr; +use der::SecretDocument; + +use elliptic_curve::{array::typenum::Unsigned, Error, zeroize::Zeroizing}; +use pkcs8::{AssociatedOid, DecodePrivateKey, EncodePrivateKey, ObjectIdentifier, spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier}}; + +#[cfg(feature = "arithmetic")] +use crate::{BignP256, elliptic_curve::rand_core::CryptoRngCore, NonZeroScalar, Result}; +use crate::{ALGORITHM_OID, PublicKey, ScalarPrimitive, SecretKey}; +#[cfg(feature = "arithmetic")] +use crate::FieldBytes; + +impl SecretKey { + const MIN_SIZE: usize = 24; + + /// Generate a random [`SecretKey`]. + #[cfg(feature = "arithmetic")] + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + Self { + inner: NonZeroScalar::random(rng).into(), + } + } + + /// Borrow the inner secret [`elliptic_curve::ScalarPrimitive`] value. + /// + /// # ⚠️ Warning + /// + /// This value is key material. + /// + /// Please treat it with the care it deserves! + pub fn as_scalar_primitive(&self) -> &ScalarPrimitive { + &self.inner + } + + /// Get the secret [`elliptic_curve::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 { + (*self).into() + } + + /// Get the [`PublicKey`] which corresponds to this secret key + #[cfg(feature = "arithmetic")] + pub fn public_key(&self) -> PublicKey { + PublicKey::from_secret_scalar(&self.to_nonzero_scalar()) + } + + /// Deserialize secret key from an encoded secret scalar. + pub fn from_bytes(bytes: &FieldBytes) -> Result { + let inner: ScalarPrimitive = + 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-bytes) and at most + /// `C::FieldBytesSize` bytes in length. + /// + /// Byte slices shorter than the field size are handled by zero padding the input. + /// + /// NOTE: this function is variable-time with respect to the input length. To avoid a timing + /// sidechannel, always ensure that the input has been pre-padded to `C::FieldBytesSize`. + pub fn from_slice(slice: &[u8]) -> Result { + if slice.len() == ::FieldBytesSize::USIZE { + Self::from_bytes(FieldBytes::from_slice(slice)) + } else if (Self::MIN_SIZE..::FieldBytesSize::USIZE) + .contains(&slice.len()) + { + let mut bytes = Zeroizing::new(FieldBytes::default()); + let offset = ::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 { + self.inner.to_bytes() + } +} + +impl From for NonZeroScalar { + fn from(secret_key: SecretKey) -> NonZeroScalar { + secret_key.to_nonzero_scalar() + } +} + +#[cfg(feature = "arithmetic")] +impl From for SecretKey { + fn from(scalar: NonZeroScalar) -> SecretKey { + SecretKey::from(&scalar) + } +} + +#[cfg(feature = "arithmetic")] +impl From<&NonZeroScalar> for SecretKey { + fn from(scalar: &NonZeroScalar) -> SecretKey { + SecretKey { + inner: scalar.into(), + } + } +} + +impl AssociatedAlgorithmIdentifier for SecretKey { + type Params = ObjectIdentifier; + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some(BignP256::OID), + }; +} + +impl TryFrom> for SecretKey { + type Error = pkcs8::Error; + + fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + private_key_info + .algorithm + .assert_oids(ALGORITHM_OID, BignP256::OID)?; + Self::from_slice(private_key_info.private_key).map_err(|_| pkcs8::Error::KeyMalformed) + } +} + +#[cfg(feature = "pem")] +impl FromStr for SecretKey { + type Err = Error; + fn from_str(s: &str) -> std::result::Result { + Self::from_pkcs8_pem(s).map_err(|_| Error) + } +} + +impl EncodePrivateKey for SecretKey { + fn to_pkcs8_der(&self) -> pkcs8::Result { + let algorithm_identifier = pkcs8::AlgorithmIdentifierRef { + oid: ALGORITHM_OID, + parameters: Some((&BignP256::OID).into()), + }; + + let ec_private_key = self.to_bytes(); + let pkcs8_key = pkcs8::PrivateKeyInfo::new(algorithm_identifier, &ec_private_key); + Ok(SecretDocument::encode_msg(&pkcs8_key)?) + } +} diff --git a/bign256/tests/dsa.rs b/bign256/tests/dsa.rs index 4ef5428d..96c88604 100644 --- a/bign256/tests/dsa.rs +++ b/bign256/tests/dsa.rs @@ -1,23 +1,24 @@ //! bign256 DSA Tests -#![cfg(feature = "dsa")] +#![cfg(feature = "ecdsa")] + +use elliptic_curve::ops::Reduce; +use hex_literal::hex; +use proptest::prelude::*; use bign256::{ - dsa::{ + ecdsa::{ signature::{Signer, Verifier}, Signature, SigningKey, VerifyingKey, }, NonZeroScalar, Scalar, U256, }; -use elliptic_curve::ops::Reduce; -use hex_literal::hex; -use proptest::prelude::*; -const PUBLIC_KEY: [u8; 65] = hex!( - "04 - D07F8590A8F77BF84F1EF10C6DE44CF5DDD52B4C9DE4CE3FE0799D1750561ABD - 909AD9B92A4DB89A4A050959DA2E0C1926281B466D68913417C8E86103A6C67A" +const PUBLIC_KEY: [u8; 64] = hex!( + "BD1A5650 179D79E0 3FCEE49D 4C2BD5DD F54CE46D 0CF11E4F F87BF7A8 90857FD0" + "7AC6A603 61E8C817 3491686D 461B2826 190C2EDA 5909054A 9AB84D2A B9D99A90" ); + const MSG: &[u8] = b"testing"; const SIG: [u8; 48] = hex!( "63F59C523FF1780851143114FFBC5C13" @@ -26,7 +27,7 @@ const SIG: [u8; 48] = hex!( #[test] fn verify_test_vector() { - let vk = VerifyingKey::from_sec1_bytes(&PUBLIC_KEY).unwrap(); + let vk = VerifyingKey::from_bytes(&PUBLIC_KEY).unwrap(); let sig = Signature::try_from(&SIG).unwrap(); assert!(vk.verify(MSG, &sig).is_ok()); } diff --git a/bign256/tests/ecdh.rs b/bign256/tests/ecdh.rs new file mode 100644 index 00000000..7dd58fb4 --- /dev/null +++ b/bign256/tests/ecdh.rs @@ -0,0 +1,29 @@ +#![cfg(feature = "ecdh")] +#[test] +fn ecdh() { + use bign256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; + use rand_core::OsRng; // requires 'getrandom' feature + + // Alice + let alice_secret = EphemeralSecret::random(&mut OsRng); + let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); + + // Bob + let bob_secret = EphemeralSecret::random(&mut OsRng); + let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); + + // Alice decodes Bob's serialized public key and computes a shared secret from it + let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) + .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! + + let alice_shared = alice_secret.diffie_hellman(&bob_public); + + // Bob decodes Alice's serialized public key and computes the same shared secret + let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) + .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! + + let bob_shared = bob_secret.diffie_hellman(&alice_public); + + // Both participants arrive on the same shared secret + assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); +} \ No newline at end of file diff --git a/bign256/tests/examples/pkcs8-private.der b/bign256/tests/examples/pkcs8-private.der new file mode 100644 index 0000000000000000000000000000000000000000..4b293bb76fb9f215d58eb67a226230d85dfd2704 GIT binary patch literal 65 zcmXr8XJTY9kYMA|Dqvt@P)gNhVnnc+8CewM)3)yLF1Ac}HU3~Ur{t4_iH7`Jb|a^G NJeA7vhl(F%0sx3Y5V8OO literal 0 HcmV?d00001 diff --git a/bign256/tests/examples/pkcs8-private.pem b/bign256/tests/examples/pkcs8-private.pem new file mode 100644 index 00000000..e581587f --- /dev/null +++ b/bign256/tests/examples/pkcs8-private.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +MD8CAQAwGAYKKnAAAgAiZS0CAQYKKnAAAgAiZS0DAQQgH2a1uEtzOWdFM/AynHTy +GDQoH+0HMkKeDHkjX8Jz4mk= +-----END PRIVATE KEY----- diff --git a/bign256/tests/examples/pkcs8-public.der b/bign256/tests/examples/pkcs8-public.der new file mode 100644 index 0000000000000000000000000000000000000000..f5b0cf251e1d8a7ed25b7547cfe48c50fe98a55f GIT binary patch literal 95 zcmXqrHIQKA(kftJVo*xeWnx6InHiZK88+RRS(5Ww*J6UqdnY%`R|bC<6>&d5xXYep uk74X5N9~msd@J5O_`ZBs-O5zmT}Q2(sxKY-9of=0().unwrap(); + + // Ensure key parses equivalently to DER + let der_key = SecretKey::from_pkcs8_der(&PKCS8_PRIVATE_KEY_DER[..]).unwrap(); + assert_eq!(secret_key.to_bytes(), der_key.to_bytes()); +} + +#[test] +#[cfg(feature = "pem")] +fn decode_pkcs8_public_key_from_pem() { + let public_key = PKCS8_PUBLIC_KEY_PEM.parse::().unwrap(); + + // Ensure key parses equivalently to DER + let der_key = PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + assert_eq!(public_key, der_key); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_pkcs8_private_key_to_der() { + let original_secret_key = SecretKey::from_pkcs8_der(&PKCS8_PRIVATE_KEY_DER[..]).unwrap(); + let reencoded_secret_key = original_secret_key.to_pkcs8_der(); + assert_eq!(reencoded_secret_key.unwrap().to_bytes().to_vec(), &PKCS8_PRIVATE_KEY_DER[..]); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_pkcs8_public_key_to_der() { + let original_public_key = + PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let reencoded_public_key = original_public_key.to_public_key_der().unwrap(); + assert_eq!(reencoded_public_key.as_ref(), &PKCS8_PUBLIC_KEY_DER[..]); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_pkcs8_private_key_to_pem() { + let original_secret_key = SecretKey::from_pkcs8_der(&PKCS8_PRIVATE_KEY_DER[..]).unwrap(); + let reencoded_secret_key = original_secret_key + .to_pkcs8_pem(Default::default()) + .unwrap(); + assert_eq!(reencoded_secret_key.as_str(), PKCS8_PRIVATE_KEY_PEM); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_pkcs8_public_key_to_pem() { + let original_public_key = + PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let reencoded_public_key = original_public_key.to_string(); + assert_eq!(reencoded_public_key.as_str(), PKCS8_PUBLIC_KEY_PEM); +} From 3e9f2aa4a013882f158458c559fb000caf269c0e Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Fri, 10 May 2024 17:16:06 +0300 Subject: [PATCH 02/12] remove patch --- Cargo.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0845a36c..126bda12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,3 @@ members = [ [profile.dev] opt-level = 2 - -[patch.crates-io] -#pkcs8 = { path = "/Users/makavity/dev/crypto/formats/pkcs8" } -const-oid = { path = "/Users/makavity/dev/crypto/formats/const-oid"} \ No newline at end of file From 4c56ebd70b11a8ad6ea0d4042cc69ba8d61b7414 Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Fri, 10 May 2024 20:38:40 +0300 Subject: [PATCH 03/12] add ecdh + fixes --- Cargo.lock | 5 + bign256/Cargo.toml | 10 +- bign256/src/ecdh.rs | 248 ++++++++++++++++++++++++++++----- bign256/src/ecdsa/verifying.rs | 4 +- bign256/src/lib.rs | 12 +- bign256/src/public_key.rs | 43 ++++-- bign256/tests/ecdh.rs | 4 +- bign256/tests/pkcs8.rs | 2 +- 8 files changed, 269 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c045f4d..7bddb719 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,12 @@ dependencies = [ "belt-hash", "criterion", "der", + "digest", "elliptic-curve", "hex", "hex-literal", + "hkdf", + "hmac", "pkcs8", "primeorder", "proptest", @@ -221,6 +224,8 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "const-oid" version = "0.10.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e3352a27098ba6b09546e5f13b15165e6a88b5c2723afecb3ea9576b27e3ea" [[package]] name = "cpufeatures" diff --git a/bign256/Cargo.toml b/bign256/Cargo.toml index 12076348..d053f311 100644 --- a/bign256/Cargo.toml +++ b/bign256/Cargo.toml @@ -27,7 +27,11 @@ rfc6979 = { version = "=0.5.0-pre.3", optional = true } rand_core = "0.6.4" pkcs8 = { version = "0.11.0-pre.0", optional = true } sec1 = { version = "0.8.0-pre.1", optional = true } -der = { version = "0.8.0-pre.0" } +der = { version = "0.8.0-pre.0" } + +digest = { version = "0.11.0-pre.8", optional = true } +hkdf = { version = "0.13.0-pre.3", optional = true } +hmac = { version = "0.13.0-pre.3", optional = true } [dev-dependencies] criterion = "0.5" @@ -37,7 +41,7 @@ rand_core = { version = "0.6", features = ["getrandom"] } hex = { version = "0.4" } [features] -default = ["arithmetic", "pkcs8", "std", "ecdsa", "pem"] +default = ["arithmetic", "pkcs8", "std", "ecdsa", "pem", "ecdh"] alloc = ["elliptic-curve/alloc", "primeorder?/alloc"] std = ["alloc", "elliptic-curve/std", "signature?/std"] @@ -45,7 +49,7 @@ ecdsa = ["arithmetic", "dep:rfc6979", "dep:signature", "dep:belt-hash"] arithmetic = ["dep:primeorder", "elliptic-curve/arithmetic"] pem = ["pkcs8", "sec1/pem"] pkcs8 = ["dep:pkcs8"] -ecdh = ["arithmetic", "elliptic-curve/ecdh"] +ecdh = ["arithmetic", "elliptic-curve/ecdh", "dep:digest", "dep:hkdf", "dep:hmac", "dep:belt-hash"] [[bench]] name = "field" diff --git a/bign256/src/ecdh.rs b/bign256/src/ecdh.rs index bbe3681d..5579864d 100644 --- a/bign256/src/ecdh.rs +++ b/bign256/src/ecdh.rs @@ -1,47 +1,225 @@ -//! Elliptic Curve Diffie-Hellman (Ephemeral) Support. +//! Elliptic Curve Diffie-Hellman Support. //! -//! This module contains a high-level interface for performing ephemeral -//! Diffie-Hellman key exchanges using the bign256 elliptic curve. +//! # ECDH Ephemeral (ECDHE) Usage //! -//! # Usage +//! Ephemeral Diffie-Hellman provides a one-time key exchange between two peers +//! using a randomly generated set of keys for each exchange. //! -//! This usage example is from the perspective of two participants in the -//! exchange, nicknamed "Alice" and "Bob". +//! 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) //! -//! ``` -//! use bign256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; -//! use rand_core::OsRng; // requires 'getrandom' feature +//! See the documentation for the [`EphemeralSecret`] type for more information +//! on performing ECDH ephemeral key exchanges. //! -//! // Alice -//! let alice_secret = EphemeralSecret::random(&mut OsRng); -//! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); +//! # Static ECDH Usage //! -//! // Bob -//! let bob_secret = EphemeralSecret::random(&mut OsRng); -//! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); +//! Static ECDH key exchanges are supported via the low-level +//! [`diffie_hellman`] function. //! -//! // Alice decodes Bob's serialized public key and computes a shared secret from it -//! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) -//! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! -//! -//! let alice_shared = alice_secret.diffie_hellman(&bob_public); -//! -//! // Bob decodes Alice's serialized public key and computes the same shared secret -//! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) -//! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! -//! -//! let bob_shared = bob_secret.diffie_hellman(&alice_public); -//! -//! // Both participants arrive on the same shared secret -//! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); -//! ``` +//! [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}; + +use core::borrow::Borrow; +use belt_hash::BeltHash; +use elliptic_curve::point::AffineCoordinates; +use hkdf::Hkdf; +use hmac::SimpleHmac; +use rand_core::CryptoRngCore; +use elliptic_curve::zeroize::{Zeroize, ZeroizeOnDrop}; +use crate::{AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey}; + +/// 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( + secret_key: impl Borrow, + public_key: impl Borrow, +) -> SharedSecret +{ + let public_point = ProjectivePoint::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 +{ + scalar: NonZeroScalar, +} + +impl EphemeralSecret +{ + /// Generate a cryptographically random [`EphemeralSecret`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + Self { + scalar: NonZeroScalar::random(rng), + } + } -pub use elliptic_curve::ecdh::diffie_hellman; + /// Get the public key associated with this ephemeral secret. + /// + /// The `compress` flag enables point compression. + pub fn public_key(&self) -> PublicKey { + PublicKey::from_secret_scalar(&self.scalar) + } -use crate::BignP256; + /// 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) -> SharedSecret { + diffie_hellman(self.scalar, public_key.as_affine()) + } +} -/// NIST P-256 Ephemeral Diffie-Hellman Secret. -pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; +impl From<&EphemeralSecret> for PublicKey +{ + fn from(ephemeral_secret: &EphemeralSecret) -> Self { + ephemeral_secret.public_key() + } +} + +impl Zeroize for EphemeralSecret +{ + fn zeroize(&mut self) { + self.scalar.zeroize() + } +} + +impl ZeroizeOnDrop for EphemeralSecret {} + +impl Drop for EphemeralSecret +{ + fn drop(&mut self) { + self.zeroize(); + } +} /// Shared secret value computed via ECDH key agreement. -pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; +pub struct SharedSecret { + /// Computed secret value + secret_bytes: FieldBytes, +} + +impl SharedSecret { + /// Create a new [`SharedSecret`] from an [`AffinePoint`] for this curve. + #[inline] + fn new(point: AffinePoint) -> Self + { + 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(&self, salt: Option<&[u8]>) -> Hkdf> + { + 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 { + &self.secret_bytes + } +} + +impl From for SharedSecret { + /// 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) -> Self { + Self { secret_bytes } + } +} + +impl ZeroizeOnDrop for SharedSecret {} + +impl Drop for SharedSecret { + fn drop(&mut self) { + self.secret_bytes.zeroize() + } +} diff --git a/bign256/src/ecdsa/verifying.rs b/bign256/src/ecdsa/verifying.rs index 54438f8f..5bd78176 100644 --- a/bign256/src/ecdsa/verifying.rs +++ b/bign256/src/ecdsa/verifying.rs @@ -84,13 +84,13 @@ impl VerifyingKey { hasher.update(msg); hasher.finalize_fixed() } - + /// Parse a [`VerifyingKey`] from a byte slice. pub fn from_bytes(bytes: &[u8]) -> Result { let public_key = PublicKey::from_bytes(bytes).map_err(|_| Error::new())?; Self::new(public_key) } - + /// Serialize the [`VerifyingKey`] as a byte array. #[cfg(feature = "alloc")] pub fn to_bytes(&self) -> Box<[u8]> { diff --git a/bign256/src/lib.rs b/bign256/src/lib.rs index 036459ff..94926936 100644 --- a/bign256/src/lib.rs +++ b/bign256/src/lib.rs @@ -30,7 +30,9 @@ extern crate alloc; pub use elliptic_curve::{self, bigint::U256}; -use elliptic_curve::{bigint::ArrayEncoding, consts::U32, Error, FieldBytesEncoding}; +use elliptic_curve::{ + bigint::ArrayEncoding, consts::U32, Error, FieldBytesEncoding, +}; #[cfg(feature = "arithmetic")] pub use arithmetic::{AffinePoint, ProjectivePoint, scalar::Scalar}; @@ -44,10 +46,10 @@ pub mod arithmetic; #[cfg(any(feature = "test-vectors", test))] pub mod test_vectors; -#[cfg(feature = "ecdsa")] -pub mod ecdsa; #[cfg(feature = "ecdh")] pub mod ecdh; +#[cfg(feature = "ecdsa")] +pub mod ecdsa; #[cfg(feature = "arithmetic")] pub mod public_key; #[cfg(feature = "arithmetic")] @@ -142,7 +144,8 @@ pub type ScalarPrimitive = elliptic_curve::ScalarPrimitive; /// Elliptic curve BignP256 public key. #[cfg(feature = "arithmetic")] #[derive(Clone, Debug, Eq, PartialEq)] -pub struct PublicKey { +pub struct PublicKey +{ point: elliptic_curve::AffinePoint, } @@ -153,6 +156,7 @@ pub struct SecretKey { inner: ScalarPrimitive, } + /// Bit representation of a BIGN P-256 scalar field element. #[cfg(feature = "bits")] pub type ScalarBits = elliptic_curve::ScalarBits; diff --git a/bign256/src/public_key.rs b/bign256/src/public_key.rs index f0c6eba4..2e567dd4 100644 --- a/bign256/src/public_key.rs +++ b/bign256/src/public_key.rs @@ -5,22 +5,17 @@ use core::str::FromStr; use elliptic_curve::{ AffinePoint, - CurveArithmetic, - Error, - Group, array::Array, - point::NonIdentity, - sec1::{FromEncodedPoint, ToEncodedPoint} + CurveArithmetic, + Error, Group, point::NonIdentity, sec1::{FromEncodedPoint, ToEncodedPoint}, }; use pkcs8::{ AssociatedOid, - DecodePublicKey, - EncodePublicKey, - ObjectIdentifier, - spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier} + DecodePublicKey, EncodePublicKey, ObjectIdentifier, spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier}, }; use crate::{ALGORITHM_OID, BignP256, EncodedPoint, NonZeroScalar, ProjectivePoint, PublicKey}; + impl PublicKey { /// Convert an [`AffinePoint`] into a [`PublicKey`] pub fn from_affine(point: AffinePoint) -> Result { @@ -70,9 +65,22 @@ impl PublicKey { let affine = AffinePoint::::from_encoded_point(&point); if affine.is_none().into() { Err(Error) + } else { + Ok(Self { + point: affine.unwrap(), + }) } - else { - Ok(Self { point: affine.unwrap() }) + } + + /// Get [`PublicKey`] from encoded point + pub fn from_encoded_point(point: EncodedPoint) -> Result { + let affine = AffinePoint::::from_encoded_point(&point); + if affine.is_none().into() { + Err(Error) + } else { + Ok(Self { + point: affine.unwrap(), + }) } } @@ -84,6 +92,12 @@ impl PublicKey { bytes[33..].reverse(); bytes[1..].to_vec().into_boxed_slice() } + + #[cfg(feature = "alloc")] + /// Get encoded point from [`PublicKey`] + pub fn to_encoded_point(&self) -> EncodedPoint { + self.point.to_encoded_point(false) + } } impl AsRef> for PublicKey { @@ -167,6 +181,12 @@ impl EncodePublicKey for PublicKey { } } +impl From for EncodedPoint { + fn from(value: PublicKey) -> Self { + value.point.to_encoded_point(false) + } +} + #[cfg(feature = "pem")] impl FromStr for PublicKey { type Err = Error; @@ -187,4 +207,3 @@ impl Display for PublicKey { ) } } - diff --git a/bign256/tests/ecdh.rs b/bign256/tests/ecdh.rs index 7dd58fb4..08bf0bc1 100644 --- a/bign256/tests/ecdh.rs +++ b/bign256/tests/ecdh.rs @@ -13,13 +13,13 @@ fn ecdh() { let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); // Alice decodes Bob's serialized public key and computes a shared secret from it - let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) + let bob_public = PublicKey::from_encoded_point(bob_pk_bytes) .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! let alice_shared = alice_secret.diffie_hellman(&bob_public); // Bob decodes Alice's serialized public key and computes the same shared secret - let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) + let alice_public = PublicKey::from_encoded_point(alice_pk_bytes) .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! let bob_shared = bob_secret.diffie_hellman(&alice_public); diff --git a/bign256/tests/pkcs8.rs b/bign256/tests/pkcs8.rs index 8e28db05..785041d9 100644 --- a/bign256/tests/pkcs8.rs +++ b/bign256/tests/pkcs8.rs @@ -3,7 +3,7 @@ use hex_literal::hex; use pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}; -use bign256::{BignP256, PublicKey, SecretKey}; +use bign256::{PublicKey, SecretKey}; const PKCS8_PRIVATE_KEY_DER: &[u8; 65] = include_bytes!("examples/pkcs8-private.der"); #[cfg(feature = "pem")] From e2cc8a3c9c074873ffa780d9225c58b7b534d006 Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Fri, 10 May 2024 20:40:25 +0300 Subject: [PATCH 04/12] fix clippy + fmt --- bign256/src/arithmetic/scalar.rs | 2 +- bign256/src/ecdh.rs | 31 ++++++++++++------------------- bign256/src/ecdsa/verifying.rs | 4 +++- bign256/src/lib.rs | 10 +++------- bign256/src/public_key.rs | 16 ++++++++-------- bign256/src/secret_key.rs | 13 ++++++++----- bign256/tests/ecdh.rs | 17 ++++++++++------- bign256/tests/pkcs8.rs | 11 ++++++----- 8 files changed, 51 insertions(+), 53 deletions(-) diff --git a/bign256/src/arithmetic/scalar.rs b/bign256/src/arithmetic/scalar.rs index 2fecc778..340f5169 100644 --- a/bign256/src/arithmetic/scalar.rs +++ b/bign256/src/arithmetic/scalar.rs @@ -15,7 +15,7 @@ mod scalar_impl; use self::scalar_impl::*; -use crate::{BignP256, FieldBytes, FieldBytesEncoding, ORDER_HEX, SecretKey, U256}; +use crate::{BignP256, FieldBytes, FieldBytesEncoding, SecretKey, ORDER_HEX, U256}; use core::{ iter::{Product, Sum}, ops::{AddAssign, MulAssign, Neg, Shr, ShrAssign, SubAssign}, diff --git a/bign256/src/ecdh.rs b/bign256/src/ecdh.rs index 5579864d..34b491e1 100644 --- a/bign256/src/ecdh.rs +++ b/bign256/src/ecdh.rs @@ -33,14 +33,14 @@ // use rand_core::CryptoRngCore; // use zeroize::{Zeroize, ZeroizeOnDrop}; -use core::borrow::Borrow; +use crate::{AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey}; use belt_hash::BeltHash; +use core::borrow::Borrow; use elliptic_curve::point::AffineCoordinates; +use elliptic_curve::zeroize::{Zeroize, ZeroizeOnDrop}; use hkdf::Hkdf; use hmac::SimpleHmac; use rand_core::CryptoRngCore; -use elliptic_curve::zeroize::{Zeroize, ZeroizeOnDrop}; -use crate::{AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey}; /// Low-level Elliptic Curve Diffie-Hellman (ECDH) function. /// @@ -65,9 +65,9 @@ use crate::{AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey}; pub fn diffie_hellman( secret_key: impl Borrow, public_key: impl Borrow, -) -> SharedSecret -{ +) -> SharedSecret { let public_point = ProjectivePoint::from(*public_key.borrow()); + #[allow(clippy::arithmetic_side_effects)] let secret_point = (public_point * secret_key.borrow().as_ref()).to_affine(); SharedSecret::new(secret_point) } @@ -93,13 +93,11 @@ pub fn diffie_hellman( /// /// 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 -{ +pub struct EphemeralSecret { scalar: NonZeroScalar, } -impl EphemeralSecret -{ +impl EphemeralSecret { /// Generate a cryptographically random [`EphemeralSecret`]. pub fn random(rng: &mut impl CryptoRngCore) -> Self { Self { @@ -121,15 +119,13 @@ impl EphemeralSecret } } -impl From<&EphemeralSecret> for PublicKey -{ +impl From<&EphemeralSecret> for PublicKey { fn from(ephemeral_secret: &EphemeralSecret) -> Self { ephemeral_secret.public_key() } } -impl Zeroize for EphemeralSecret -{ +impl Zeroize for EphemeralSecret { fn zeroize(&mut self) { self.scalar.zeroize() } @@ -137,8 +133,7 @@ impl Zeroize for EphemeralSecret impl ZeroizeOnDrop for EphemeralSecret {} -impl Drop for EphemeralSecret -{ +impl Drop for EphemeralSecret { fn drop(&mut self) { self.zeroize(); } @@ -153,8 +148,7 @@ pub struct SharedSecret { impl SharedSecret { /// Create a new [`SharedSecret`] from an [`AffinePoint`] for this curve. #[inline] - fn new(point: AffinePoint) -> Self - { + fn new(point: AffinePoint) -> Self { Self { secret_bytes: point.x(), } @@ -180,8 +174,7 @@ impl SharedSecret { /// material. /// /// [HKDF]: https://en.wikipedia.org/wiki/HKDF - pub fn extract(&self, salt: Option<&[u8]>) -> Hkdf> - { + pub fn extract(&self, salt: Option<&[u8]>) -> Hkdf> { Hkdf::new(salt, &self.secret_bytes) } diff --git a/bign256/src/ecdsa/verifying.rs b/bign256/src/ecdsa/verifying.rs index 5bd78176..63442f3d 100644 --- a/bign256/src/ecdsa/verifying.rs +++ b/bign256/src/ecdsa/verifying.rs @@ -15,7 +15,9 @@ //! ``` use super::{Signature, BELT_OID}; -use crate::{AffinePoint, BignP256, EncodedPoint, FieldBytes, Hash, ProjectivePoint, PublicKey, Scalar}; +use crate::{ + AffinePoint, BignP256, EncodedPoint, FieldBytes, Hash, ProjectivePoint, PublicKey, Scalar, +}; use belt_hash::{ digest::{Digest, FixedOutput}, BeltHash, diff --git a/bign256/src/lib.rs b/bign256/src/lib.rs index 94926936..a74cfd6f 100644 --- a/bign256/src/lib.rs +++ b/bign256/src/lib.rs @@ -30,12 +30,10 @@ extern crate alloc; pub use elliptic_curve::{self, bigint::U256}; -use elliptic_curve::{ - bigint::ArrayEncoding, consts::U32, Error, FieldBytesEncoding, -}; +use elliptic_curve::{bigint::ArrayEncoding, consts::U32, Error, FieldBytesEncoding}; #[cfg(feature = "arithmetic")] -pub use arithmetic::{AffinePoint, ProjectivePoint, scalar::Scalar}; +pub use arithmetic::{scalar::Scalar, AffinePoint, ProjectivePoint}; /// Bign256 result type pub type Result = core::result::Result; @@ -144,8 +142,7 @@ pub type ScalarPrimitive = elliptic_curve::ScalarPrimitive; /// Elliptic curve BignP256 public key. #[cfg(feature = "arithmetic")] #[derive(Clone, Debug, Eq, PartialEq)] -pub struct PublicKey -{ +pub struct PublicKey { point: elliptic_curve::AffinePoint, } @@ -156,7 +153,6 @@ pub struct SecretKey { inner: ScalarPrimitive, } - /// Bit representation of a BIGN P-256 scalar field element. #[cfg(feature = "bits")] pub type ScalarBits = elliptic_curve::ScalarBits; diff --git a/bign256/src/public_key.rs b/bign256/src/public_key.rs index 2e567dd4..68530c73 100644 --- a/bign256/src/public_key.rs +++ b/bign256/src/public_key.rs @@ -4,17 +4,17 @@ use core::fmt::Display; use core::str::FromStr; use elliptic_curve::{ - AffinePoint, array::Array, - CurveArithmetic, - Error, Group, point::NonIdentity, sec1::{FromEncodedPoint, ToEncodedPoint}, + point::NonIdentity, + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, CurveArithmetic, Error, Group, }; use pkcs8::{ - AssociatedOid, - DecodePublicKey, EncodePublicKey, ObjectIdentifier, spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier}, + spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier}, + AssociatedOid, DecodePublicKey, EncodePublicKey, ObjectIdentifier, }; -use crate::{ALGORITHM_OID, BignP256, EncodedPoint, NonZeroScalar, ProjectivePoint, PublicKey}; +use crate::{BignP256, EncodedPoint, NonZeroScalar, ProjectivePoint, PublicKey, ALGORITHM_OID}; impl PublicKey { /// Convert an [`AffinePoint`] into a [`PublicKey`] @@ -71,7 +71,7 @@ impl PublicKey { }) } } - + /// Get [`PublicKey`] from encoded point pub fn from_encoded_point(point: EncodedPoint) -> Result { let affine = AffinePoint::::from_encoded_point(&point); @@ -92,7 +92,7 @@ impl PublicKey { bytes[33..].reverse(); bytes[1..].to_vec().into_boxed_slice() } - + #[cfg(feature = "alloc")] /// Get encoded point from [`PublicKey`] pub fn to_encoded_point(&self) -> EncodedPoint { diff --git a/bign256/src/secret_key.rs b/bign256/src/secret_key.rs index 9390d1f6..f4e70a1a 100644 --- a/bign256/src/secret_key.rs +++ b/bign256/src/secret_key.rs @@ -3,14 +3,17 @@ use core::str::FromStr; use der::SecretDocument; -use elliptic_curve::{array::typenum::Unsigned, Error, zeroize::Zeroizing}; -use pkcs8::{AssociatedOid, DecodePrivateKey, EncodePrivateKey, ObjectIdentifier, spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier}}; +use elliptic_curve::{array::typenum::Unsigned, zeroize::Zeroizing, Error}; +use pkcs8::{ + spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier}, + AssociatedOid, DecodePrivateKey, EncodePrivateKey, ObjectIdentifier, +}; -#[cfg(feature = "arithmetic")] -use crate::{BignP256, elliptic_curve::rand_core::CryptoRngCore, NonZeroScalar, Result}; -use crate::{ALGORITHM_OID, PublicKey, ScalarPrimitive, SecretKey}; #[cfg(feature = "arithmetic")] use crate::FieldBytes; +#[cfg(feature = "arithmetic")] +use crate::{elliptic_curve::rand_core::CryptoRngCore, BignP256, NonZeroScalar, Result}; +use crate::{PublicKey, ScalarPrimitive, SecretKey, ALGORITHM_OID}; impl SecretKey { const MIN_SIZE: usize = 24; diff --git a/bign256/tests/ecdh.rs b/bign256/tests/ecdh.rs index 08bf0bc1..7b070d8f 100644 --- a/bign256/tests/ecdh.rs +++ b/bign256/tests/ecdh.rs @@ -1,7 +1,7 @@ #![cfg(feature = "ecdh")] #[test] fn ecdh() { - use bign256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; + use bign256::{ecdh::EphemeralSecret, EncodedPoint, PublicKey}; use rand_core::OsRng; // requires 'getrandom' feature // Alice @@ -13,17 +13,20 @@ fn ecdh() { let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); // Alice decodes Bob's serialized public key and computes a shared secret from it - let bob_public = PublicKey::from_encoded_point(bob_pk_bytes) - .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! + let bob_public = + PublicKey::from_encoded_point(bob_pk_bytes).expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! let alice_shared = alice_secret.diffie_hellman(&bob_public); // Bob decodes Alice's serialized public key and computes the same shared secret - let alice_public = PublicKey::from_encoded_point(alice_pk_bytes) - .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! + let alice_public = + PublicKey::from_encoded_point(alice_pk_bytes).expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! let bob_shared = bob_secret.diffie_hellman(&alice_public); // Both participants arrive on the same shared secret - assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); -} \ No newline at end of file + assert_eq!( + alice_shared.raw_secret_bytes(), + bob_shared.raw_secret_bytes() + ); +} diff --git a/bign256/tests/pkcs8.rs b/bign256/tests/pkcs8.rs index 785041d9..7d434a6f 100644 --- a/bign256/tests/pkcs8.rs +++ b/bign256/tests/pkcs8.rs @@ -54,14 +54,16 @@ fn decode_pkcs8_public_key_from_pem() { fn encode_pkcs8_private_key_to_der() { let original_secret_key = SecretKey::from_pkcs8_der(&PKCS8_PRIVATE_KEY_DER[..]).unwrap(); let reencoded_secret_key = original_secret_key.to_pkcs8_der(); - assert_eq!(reencoded_secret_key.unwrap().to_bytes().to_vec(), &PKCS8_PRIVATE_KEY_DER[..]); + assert_eq!( + reencoded_secret_key.unwrap().to_bytes().to_vec(), + &PKCS8_PRIVATE_KEY_DER[..] + ); } #[test] #[cfg(feature = "pem")] fn encode_pkcs8_public_key_to_der() { - let original_public_key = - PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let original_public_key = PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); let reencoded_public_key = original_public_key.to_public_key_der().unwrap(); assert_eq!(reencoded_public_key.as_ref(), &PKCS8_PUBLIC_KEY_DER[..]); } @@ -79,8 +81,7 @@ fn encode_pkcs8_private_key_to_pem() { #[test] #[cfg(feature = "pem")] fn encode_pkcs8_public_key_to_pem() { - let original_public_key = - PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let original_public_key = PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); let reencoded_public_key = original_public_key.to_string(); assert_eq!(reencoded_public_key.as_str(), PKCS8_PUBLIC_KEY_PEM); } From 518c1026ff26f6fb2627a0ef639207b088512911 Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Fri, 10 May 2024 20:53:11 +0300 Subject: [PATCH 05/12] fix no_std --- bign256/src/ecdsa/verifying.rs | 3 +++ bign256/src/lib.rs | 5 ++--- bign256/src/public_key.rs | 7 ++++--- bign256/src/secret_key.rs | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/bign256/src/ecdsa/verifying.rs b/bign256/src/ecdsa/verifying.rs index 63442f3d..51cab335 100644 --- a/bign256/src/ecdsa/verifying.rs +++ b/bign256/src/ecdsa/verifying.rs @@ -14,6 +14,9 @@ //! 9. Return YES. //! ``` +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + use super::{Signature, BELT_OID}; use crate::{ AffinePoint, BignP256, EncodedPoint, FieldBytes, Hash, ProjectivePoint, PublicKey, Scalar, diff --git a/bign256/src/lib.rs b/bign256/src/lib.rs index a74cfd6f..99ba984e 100644 --- a/bign256/src/lib.rs +++ b/bign256/src/lib.rs @@ -1,5 +1,4 @@ -// #![no_std] -// #![no_std] +#![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( @@ -58,7 +57,7 @@ const ALGORITHM_OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.112.0.2.0.34.101.45.2.1"); #[cfg(feature = "ecdsa")] -type Hash = belt_hash::digest::Output; +type Hash = digest::Output; /// Order of BIGN P-256's elliptic curve group (i.e. scalar modulus) in hexadecimal. const ORDER_HEX: &str = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD95C8ED60DFB4DFC7E5ABF99263D6607"; diff --git a/bign256/src/public_key.rs b/bign256/src/public_key.rs index 68530c73..c2209293 100644 --- a/bign256/src/public_key.rs +++ b/bign256/src/public_key.rs @@ -1,7 +1,8 @@ //! Public key types and traits -use core::fmt::Display; -use core::str::FromStr; +#[cfg(feature = "alloc")] +use alloc::{boxed::Box, fmt}; +use core::{fmt::Display, str::FromStr}; use elliptic_curve::{ array::Array, @@ -198,7 +199,7 @@ impl FromStr for PublicKey { #[cfg(feature = "pem")] impl Display for PublicKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", diff --git a/bign256/src/secret_key.rs b/bign256/src/secret_key.rs index f4e70a1a..00d111b9 100644 --- a/bign256/src/secret_key.rs +++ b/bign256/src/secret_key.rs @@ -142,7 +142,7 @@ impl TryFrom> for SecretKey { #[cfg(feature = "pem")] impl FromStr for SecretKey { type Err = Error; - fn from_str(s: &str) -> std::result::Result { + fn from_str(s: &str) -> core::result::Result { Self::from_pkcs8_pem(s).map_err(|_| Error) } } From 2c6b8716217b6c0a426e2ea5180e7b77e96479e4 Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Fri, 10 May 2024 21:03:12 +0300 Subject: [PATCH 06/12] maybe fix alloc --- bign256/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bign256/Cargo.toml b/bign256/Cargo.toml index d053f311..ad789ecd 100644 --- a/bign256/Cargo.toml +++ b/bign256/Cargo.toml @@ -49,7 +49,7 @@ ecdsa = ["arithmetic", "dep:rfc6979", "dep:signature", "dep:belt-hash"] arithmetic = ["dep:primeorder", "elliptic-curve/arithmetic"] pem = ["pkcs8", "sec1/pem"] pkcs8 = ["dep:pkcs8"] -ecdh = ["arithmetic", "elliptic-curve/ecdh", "dep:digest", "dep:hkdf", "dep:hmac", "dep:belt-hash"] +ecdh = ["arithmetic", "elliptic-curve/ecdh", "dep:digest", "dep:hkdf", "dep:hmac", "dep:belt-hash", "alloc"] [[bench]] name = "field" From 75a9c114112196010c5545f98e1ec3e7ac8c786b Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Fri, 10 May 2024 21:11:32 +0300 Subject: [PATCH 07/12] fix tests for no_std platforms --- bign256/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bign256/src/lib.rs b/bign256/src/lib.rs index 99ba984e..f449270b 100644 --- a/bign256/src/lib.rs +++ b/bign256/src/lib.rs @@ -26,6 +26,7 @@ )] #[cfg(feature = "alloc")] +#[allow(unused_extern_crates)] extern crate alloc; pub use elliptic_curve::{self, bigint::U256}; From f50ac39d4746e860beef6c63d5ed150ec5f8ea5e Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Fri, 10 May 2024 21:17:42 +0300 Subject: [PATCH 08/12] fix dead code linter --- bign256/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bign256/src/lib.rs b/bign256/src/lib.rs index f449270b..135b9f6b 100644 --- a/bign256/src/lib.rs +++ b/bign256/src/lib.rs @@ -54,6 +54,7 @@ pub mod public_key; pub mod secret_key; #[cfg(feature = "pkcs8")] +#[allow(dead_code)] const ALGORITHM_OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.112.0.2.0.34.101.45.2.1"); From 3c0400ccc9109407baddf23430cce9dbed654c3a Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Thu, 25 Jul 2024 10:30:01 +0300 Subject: [PATCH 09/12] update hybrid-array to rc8 --- Cargo.lock | 4 ++-- bign256/src/ecdsa/signing.rs | 2 +- bign256/src/ecdsa/verifying.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0df25b3d..ead56598 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,9 +541,9 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.2.0-rc.4" +version = "0.2.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e63b66aee2df5599ba69b17a48113dfc68d2e143ea387ef836509e433bbd7e" +checksum = "53668f5da5a41d9eaf4bf7064be46d1ebe6a4e1ceed817f387587b18f2b51047" dependencies = [ "typenum", "zeroize", diff --git a/bign256/src/ecdsa/signing.rs b/bign256/src/ecdsa/signing.rs index a4d4f577..341838f3 100644 --- a/bign256/src/ecdsa/signing.rs +++ b/bign256/src/ecdsa/signing.rs @@ -19,7 +19,7 @@ use crate::{BignP256, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey, Sca use belt_hash::{BeltHash, Digest}; use core::fmt::{self, Debug}; use elliptic_curve::{ - array::{consts::U32, typenum::Unsigned, Array}, + array::{sizes::U32, typenum::Unsigned, Array}, ops::{MulByGenerator, Reduce}, point::AffineCoordinates, subtle::{Choice, ConstantTimeEq}, diff --git a/bign256/src/ecdsa/verifying.rs b/bign256/src/ecdsa/verifying.rs index 51cab335..368b8fe5 100644 --- a/bign256/src/ecdsa/verifying.rs +++ b/bign256/src/ecdsa/verifying.rs @@ -26,7 +26,7 @@ use belt_hash::{ BeltHash, }; use elliptic_curve::{ - array::{consts::U32, typenum::Unsigned, Array}, + array::{sizes::U32, typenum::Unsigned, Array}, group::GroupEncoding, ops::{LinearCombination, Reduce}, Curve, Field, Group, From cd100e1cb48a73714a182c7626ff21714b705eeb Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Sat, 27 Jul 2024 15:25:58 +0300 Subject: [PATCH 10/12] fix test vectors for bign256 --- bign256/src/test_vectors/group.rs | 230 ++++++++++++++---------------- bign256/tests/projective.rs | 36 +++-- 2 files changed, 121 insertions(+), 145 deletions(-) diff --git a/bign256/src/test_vectors/group.rs b/bign256/src/test_vectors/group.rs index 606d089a..1d0a0b03 100644 --- a/bign256/src/test_vectors/group.rs +++ b/bign256/src/test_vectors/group.rs @@ -7,6 +7,10 @@ use hex_literal::hex; /// These are the first 20 test vectors, generated by sagemath snippet. pub const ADD_TEST_VECTORS: &[([u8; 32], [u8; 32])] = &[ // k = 1,..,20, p += G + ( + hex!("0000000000000000000000000000000000000000000000000000000000000000"), + hex!("6BF7FC3CFB16D69F5CE4C9A351D6835D78913966C408F6521E29CF1804516A93"), + ), ( hex!("2D8419E3D905D21E3611261DADC95BB35583090C2CADD0C807F53BB3828F0995"), hex!("E62690D81BDC754EFAF5B2770054564849621E8A933A7ECD6C02387649CF258A"), @@ -83,175 +87,151 @@ pub const ADD_TEST_VECTORS: &[([u8; 32], [u8; 32])] = &[ hex!("1230402EBB4A981C19506708F779C265D1695DF2132F17099D0E54BA1C46D945"), hex!("FBB7A79A4E5F631E1FD59501F221FA2FAE93F8E2CD7D4D87E1003324C327EEB7"), ), - ( - hex!("006A714979F622DBC2685A296CACA8067694D3ADC75F9F9A97F3BBA424DD2670"), - hex!("F4FD78EDF21FB1C4A23DD0B0FFD281FC35184F13D2B5D779DB7253E88097F121"), - ), ]; /// Scalar multiplication with the generator. /// /// These are the test vectors from sagemath snippet,that are not part of [`ADD_TEST_VECTORS`]. -/// k values is from NIST-P256 test vectors +/// k values is from NIST-P256 test vectors` +/// ```ignore +/// p = 2**256 - 189 +/// a = 2**256 - 192 +/// b = 0x77CE6C1515F3A8EDD2C13AABE4D8FBBE4CF55069978B9253B22E7D6BD69C03F1 +/// Gx = 0 +/// Gy = 0x6BF7FC3CFB16D69F5CE4C9A351D6835D78913966C408F6521E29CF1804516A93 +/// h = 1 +/// +/// # Create the finite field and the elliptic curve +/// F = GF(p) +/// E = EllipticCurve(F, [a, b]) +/// +/// # Define the base point +/// G = E(Gx, Gy) +/// n = G.order() +/// +/// # Generate test vectors +/// def generate_mul_test_vectors(num_vectors): +/// vectors = [] +/// for _ in range(num_vectors): +/// k = ZZ.random_element(1, n) +/// P = k * G +/// vectors.append((k, P)) +/// return vectors +/// +/// # Number of test vectors to generate +/// num_vectors = 20 +/// test_vectors = generate_mul_test_vectors(num_vectors) +/// +/// # Print the test vectors in the required format +/// for k, P in test_vectors: +/// k_hex = f"{k:064X}" +/// Px_hex = f"{int(P[0]):064X}" +/// Py_hex = f"{int(P[1]):064X}" +/// print(f' (') +/// print(f' hex!("{k_hex}"),') +/// print(f' hex!("{Px_hex}"),') +/// print(f' hex!("{Py_hex}"),') +/// print(f' ),') +/// pub const MUL_TEST_VECTORS: &[([u8; 32], [u8; 32], [u8; 32])] = &[ ( - hex!("BCE6EE467AA910ADD6FB47DF33EC4825582596B8C694DB7B403129C9427CF647"), - hex!("1D89D067B0EB566FBA7CA700A48AA90026F9584AFAA33139B890BCB21729140E"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("321D9319C3BE889BA0FD29C2E2688ABF39308A712A1D81446ED1ABC789E52CA9"), - hex!("E3B297D31A709BCD61B9861069EAEB8162237F970C11245C7E1761E2FC802B7A"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("132175D5AE957336F608DC53257205D81B088C5BDF048AF2C83B47784D70617C"), - hex!("1ADF305FCF83BA7C5B035615290644A70D381F50666D9B907673385CBCBD4791"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("BC01F7A6067E4529252C7E6F8F7D6EFA7889B8455ED042F0DE0870B419653658"), - hex!("65037BB63611DFE97DC043ED085181A4AA3A0D1D54C77C36135182ACF444265D"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("8E13BE6EAB0F05B8F0C07509DC8C17922B354ED5CF5E88D732E4EE031735319B"), - hex!("F0F23BA15E570754D21773E9D7B3D471B239415A29BB23D2C33DB3082D32966D"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("5859FC33184C7A38EE37FA61F13A47C96FF3E2D1A21347DF32297E3A7FA19FCD"), - hex!("F37B8AFF67104403A992853E307C988CE8F148E5A5D9F0091B094EC3E11CF0C0"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("1CF0FC9B67C3496E6104C6FE4CFEB03C582D6121E17B27FF5F163697021B1CA3"), - hex!("7ED1D7E43E06686AD6A050982927E54894022A55A872165CEDD82F1936800AC9"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("5251712A9696E4D3F4CC1C4B26877C200335311B03C9D53C8FC2ACE8ECECA49C"), - hex!("B04C72917AF4AAFA772314D49A2B899CD5D1D4F71FD0F18882050E61CEC361F9"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("7EF4573793DE5E95C749C810952408750B669FBFC4F177C27D74E66B95617258"), - hex!("6F7372A2DA5690F539834B9A8DD1910120E148C74F9376391F2DD41F8529DB57"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("85E00E5546713D9F2F5C8E605CA49AA16FA77CE3A3323B463599C31289697E37"), - hex!("CC258D7CA2CB8ACD629701844FE26AFE2029E127A59024E9885174E8BC35BB3F"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("796F1AA06F3366EF6C74822CD69D274D73FD7947D99E5A388D87525613C0164F"), - hex!("69FB53A5AE70C701BFCE800A78676265E87F3EDF6A1059A438B2A16A291DFEB9"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("660CEBCB17AAC38F454210254037CDE84ED2671B7C6B3531995DFAA478F01F20"), - hex!("3E752FDD0749DE0128C2A9237875413FB0C7866E9CD0F86B248272676728B6DF"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - ), - ( - hex!("108E86DBB15D670F952C36DDBADC381B7EE06052DED0C1FC369BC721F537BC21"), - hex!("35CA247AF507BE8B5FA662AFB35EB9F3DA55CB4E67FF048FA2757EBCF8ABF046"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("CED4907163D8C2250299A2FE6A9D4F8A676501B90D570D50999B9E17FD993DE6"), + hex!("7F494925F5EEA6252467D1F97951A3E00ABE75D5DC2E9837BEA227DA4FE93F32"), + hex!("7608EB9FF53DB721B99009B60058CD72BD8A1E8CFFDA35154B3B487C0330B6A3"), ), ( - hex!("62B8EBD7808F1A50B851D9080984B4A23181AF1CC60F2DE11F80CABBE27E213E"), - hex!("52A44CCB834C87D5CAA20C1B42260F9EDC1C30731C2F2F14AE2D52A7AF243794"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("8F70C9391D8143F5A0CC3F56D3132868DE940F01EF55293E61054A0DCDA13C6C"), + hex!("96F6FB31F578A3C70402655B4E18FBA6ED82052AE38465D54EF3B392EEB599DB"), + hex!("36989A75343AB812BC7EBE61DBBC8433BEF72E994BEFF339F82E9B2FC908977E"), ), ( - hex!("DD219D558AF61D9099822705054BA6F23F1378A5F482B1EC5AAD69138065B1D6"), - hex!("2C51E0EDE3618C1057E0360BECF3A550FE95E6096B9CD9326C0FEF0B68506859"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("4978C521DD195389ABC5B9C762482FCF1EAD50BF87E1209C744E50AE71596936"), + hex!("85DF197A07D0D83B5FDF0021E2494451FFB66127E7CA3645512AAD9DBF86715A"), + hex!("C5F6A22BE1583E65A6A1F4CB0309F8FFDD5C0B757FAB111D05AA40DE05D5F724"), ), ( - hex!("6C9E47CE0CCA48F4EDB53D0A02459C8D00BC670C82A4D091ADA36A158DB74DCB"), - hex!("7896936848785A4CCBBE5B39A3111EB3D36895B4ECDD911F3CBC4F08B0CE0FFC"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("5803E676B9ACA28E76B8F41E8E06DE3063964DF566BC36677A9B02383ABB652C"), + hex!("B6DC581C5BBE45D94670577696E3C260C401AF2F16D53E9886EE68993CE4A68B"), + hex!("B851D966A2C9DC5EB9CB51893BBC68356E25D70DDEC59A777E85726651114382"), ), ( - hex!("A320F2ED3C408FEB68BB456A75E14B943DA7B02B0C8A76A5737DE66F008148C4"), - hex!("C6AC14D4F31C17D720AD8A4711BD0DB84D9AE8FC6070289EA1883775D410C690"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("33486286DC0682170C1864E85A38519127246F677AAF74124C2363E223E68E50"), + hex!("11106D2AEF58FAA4894185A37F84F8EB01B5173EB9D97EC9A2B59C89654A963B"), + hex!("9F9790B9AD5CCE7B491831F8D8B34C5957716351D46BBBB644C5E04899389459"), ), ( - hex!("84221BA012EFC0694EC2DDB3B6B003FB92CD329F193D2A0A316050391DF99667"), - hex!("E91DA84671D47149BD8343291CB00F4639E90828A005176F58541F2A0DCDF185"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("FAD252070188E443F0C030E7C7ECA079851AA45EC38EA5591205A92BF72E7A8A"), + hex!("4F34B166D0F6E21398FDADDF90BD92A9466D5DC84807D12F0B26F63E6A6A6199"), + hex!("1B34BD337D078D6E3F0B1757C1EABD6E20C05903B146E307FC103E4C9D98AE86"), ), ( - hex!("F4BD16F5E8BE79055EE7B62FF8FE9381A20D2182CCE62CA77C740C7B627C0384"), - hex!("38B1E87028B46FF7742999AABB634D713DA2810C159A004E8A2C13CAF2428D96"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("6766501368501B7AECB273B176A1CB1734D10D8D680FA0DFDDD1AC655B9B1B1E"), + hex!("9F767B0EA1289232BC18599F54E3EFD3566BBC2F871A5277F8AFD8FAA4676191"), + hex!("A8F7B696569B7936C29C46087AC8DB0D22E4B0A98DA2A2E79073304341147EA8"), ), ( - hex!("99773AFF98782D076D6D759943BC1F3E9DD57A464E622A7E23ADC96413A55841"), - hex!("9BA741511B2EB4465A9CB0B21133A47A1FD9163B7946289C31221EC60E1FF8B5"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("BDE9C057B02F2A875920A93EA7E90E0ACFCFA61B725FF4273AC6EBF8F86D26C1"), + hex!("5C707BAD698506E2C8596B88F8D9E438A3CEEB0C513D95F171152522CD6F6BBB"), + hex!("AD37F0B3114D548DFE61AF0D2D20A17CF46F5FFA3E42624F0CC49A095AEF0327"), ), ( - hex!("1666D4DA3F23A9CF7EB2CE3DEF0ACB5C781F7EF080F169DF887EB39ED0CCBD48"), - hex!("C4779DF3C1F5DAAE8C0DB77BE0CF9D49F249647360A867C36A20047CF5D18CDC"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("D818D5F9167D7015E615FA914B43E926113D91F83B430E382337F9D3FE89DB44"), + hex!("331C4AEC55CFFBB0F4864532C5B21E5017A093A3848ADD18558D8B1706198E37"), + hex!("C4F73684630EA2800C5587AA6B5BAA6ECDB364DAA342D00E88BD79D73BF0DF42"), ), ( - hex!("F7D96B2CE1766AC5DF7C0CF5CDE463101334182908635F43F24B61975DE671BF"), - hex!("04B069AD735EE63E50AE27E5D7EDD6257134C6E8D8CA3AE3040001A9855682A2"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("C3550F59124BDE3BE6BEC2591D694E2528ED1410678B286DE6F626BF88FE5027"), + hex!("9029C4C081273D5708952B6F36428D16F3E0935F79187FE6992C4B494DC114A5"), + hex!("5F47621BCEE3C63EB7EF6C7E1B1301BF951928D43F91089CD48DF7B058285291"), ), ( - hex!("2F78EF54DD714BA141A893B9DEF9C14AA47900440C8C42ED90AE05D2E8665E21"), - hex!("1DDE14D0959610C2966258889FD025666B746765FCA36F6025309026145EFD3A"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("09A2AF8364E9C20C12CD68ADF99C77CFE016D602B29E702AF83233E980DCE1F4"), + hex!("C6BA1BB73E92B552D58A7585F4CBC911E05239EBFFED6681AB56C366873A204E"), + hex!("25B15BF7B8D3BE06249ACD3CBF928B79E21542FDABB2F3196D8A0561445A632A"), ), ( - hex!("3B1514BF33F6EC2C5FEEA324D04F06ECBC516B358400D67B67181029F4AF8AC9"), - hex!("0F7917B7EEAF7E7836D5FD8BDB488858CFE2E78BD9FA66757EF4D89BFAA27F69"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("DBC71EB3CEAB0EBE1E4DFC804EF0B64866720EB440A5D09FA017CBC399F62AF2"), + hex!("347262446EDF9B71B20CE9FB73CD8211959E8C5D0AC84B1FF3A3A139CA058567"), + hex!("9688F4CF75D5B8956DEABDBB420EFCB51B9F0727068B4A6D852B902B135F0A7B"), ), ( - hex!("67CC0FDF4E1735A5FCB98168158945DDE241FBA39BE2B35A5CD904CA5EB88A52"), - hex!("2C9B912969C98E7B7ED01CCDB9F32951A529BA77F40DC79B2241DA3D6FAD6C00"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("E868A23B0DA36443B119E863657D918FB2783C03191838B67D0D704747AFE887"), + hex!("43694CB57D57CF1F8B4145577888AB9A33E45778A2CAFC078A529991269A4BEE"), + hex!("6686270715CC7F94C433A4DFC8036D6C3DA4384597AEA7E4DD5685034ACACB49"), ), ( - hex!("97C9D36D07BDAA3846CDAE30E68EA4D5A84896A7A94056B4424B08B58E41BB84"), - hex!("B528D08C013362D444A9A345570E59B2E5265720B8B4F128ED6700994618990B"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("16763333BC3B7CDE3C19370CC0CECEDE456DF4F4CB1BE13F9BD4E3BCE2BC8F00"), + hex!("711AC9EB8D78CAA22CDBC82C8E777D686F22DC6AE236BC90E0A598AF8F720FA7"), + hex!("72E338F8D83E1D17A5E5A55D9D26539CFD4EEFC501FDCA6DEF36B8726FF1E85D"), ), ( - hex!("AED8D377B262039F5FA3625CBE7DDAD5129B350B9A54CE58B4E51C36DB2355B5"), - hex!("8A8B1F284CE3D769477334C6569FCFB6BAE71E8E5E1509873366A7695961B06C"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("47CD1553152E9D5194FCC4BBBD32E98F046A063D64B506E1CE01FF79DA7693E0"), + hex!("F34C6657ACF2C1FE67036FA836C82BFBFEBCDF93D22E346CC9049F24B8C512C3"), + hex!("B394717C5C37D5A08128588D5922F0798D479D4B900BC29D74EC0C76EB8622EC"), ), ( - hex!("5C01A3FEB3B295E76F091B20E652ED48A59F9AEC46CBA86160A96B59BFF6276D"), - hex!("502DBD20E1F58654546891CB66480C52155A0A45F7BD2FDE2563F2E0D5F5CD2B"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("09307AFD97C5D3854F3D513B8BA6AE4FE246C46F4A3DFA746492BB4D948E4850"), + hex!("C91132EB3ACC4FA84FC8DF11A14FE24C828947F8299696A027E49B57BA5E6F5A"), + hex!("BA5BB5DB0F6B5FFC95FCD27F9267D5004FD79539BB3C6345E4C5E5CFDF89A5B6"), ), ( - hex!("FA2879ADDCD74E29E049EAAD5279A01987D08EF515693E721572EEF5D0445278"), - hex!("332FEE155643CEFD408350C49CC776E1589770F217B2F47389FFBAE3AA8F9DE4"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("C42B1903984390E20C403560927832D02BE36B1C7EE33F1987C5241CAB8A0F63"), + hex!("D218ADD38586BD8531F45ACDFDBE8B45D5489A1CCCC8C7AA005A65B07937C96F"), + hex!("DDC12E336442E1C7BD369CDF020E7F91C9B367178C212C331A15C9E012355658"), ), ( - hex!("D0B331A63DD4815CEF494557A5CA040296E19737E0D84A8AB95C0B7404799584"), - hex!("4E982EF880233592068F58E117BE4A13EC544FB10248E10821EE4037A5466C86"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("F368D42DD35F918D4694AED51097784DE1B8F1CD204789B4E018DD36135F0CB4"), + hex!("D62675D5E732555270D6427F3C91319B0FC659F88CE45BDFB88C25B77F4BC2BA"), + hex!("C4F6ABADC81431C99E4E710F5AECFDE0B7AF4AC95DFB1635692B91EA85F4CBAF"), ), ( - hex!("51A0F158FF49D20AE469441FC627516DCB1D1161119A7B9F9531D52C8F26A36A"), - hex!("5047FC9B8057392D20057845073F58AF80DE2C1DB80D8C814AFE6C21A4033581"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("B6E9E1F518C801082FCC37B8573A0D4C5E49E65EE7E7577082F024C8A6A3C798"), + hex!("6D682C005148718B620D0C169C324C3B407BC6F1125B7623694ED7704E888832"), + hex!("0D8C0BB56FBD8174C916955580D27D40F220E27F4C514999EB3D3ADFAAC1C52E"), ), ( - hex!("F02838F64C02057A1191C490C51501A5C261A3201A0330E1A31B67FE121C9434"), - hex!("172B364C2952F8ED8771B3B152DF85A8039E9F6D7B2669E90078D2D47393902B"), - hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("B352F9B096B909607E52853CF78FBAC0F106917BD705645AF3DB53E4CAC1868D"), + hex!("F8596F4A17518F117120018C537E59AA2AEB66817DC9EEA6EC1E5AABC1A4AB77"), + hex!("DDD08D4CA61ED8B7F3F06403134CF0309ECABCD611024CF7C77BE3D8CF8E3610"), ), ]; diff --git a/bign256/tests/projective.rs b/bign256/tests/projective.rs index b0ca3bf8..dc88b319 100644 --- a/bign256/tests/projective.rs +++ b/bign256/tests/projective.rs @@ -2,27 +2,23 @@ #![cfg(all(feature = "arithmetic", feature = "test-vectors"))] -// TODO(tarcieri): these are failing -// -// use bign256::{ -// test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, -// AffinePoint, ProjectivePoint, Scalar, -// }; -// use elliptic_curve::{ -// group::{ff::PrimeField, GroupEncoding}, -// sec1::{self, ToEncodedPoint}, -// }; -// use primeorder::{impl_projective_arithmetic_tests, Double}; -// -// impl_projective_arithmetic_tests!( -// AffinePoint, -// ProjectivePoint, -// Scalar, -// ADD_TEST_VECTORS, -// MUL_TEST_VECTORS -// ); +use bign256::{ + test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, + AffinePoint, ProjectivePoint, Scalar, +}; +use elliptic_curve::{ + group::{ff::PrimeField, GroupEncoding}, + sec1::{self, ToEncodedPoint}, +}; +use primeorder::{impl_projective_arithmetic_tests, Double}; -use bign256::{elliptic_curve::group::GroupEncoding, ProjectivePoint}; +impl_projective_arithmetic_tests!( + AffinePoint, + ProjectivePoint, + Scalar, + ADD_TEST_VECTORS, + MUL_TEST_VECTORS +); #[test] fn projective_identity_to_bytes() { From 9e0627530b83e9a402e9945361e0605425f28d1b Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Sat, 27 Jul 2024 15:29:44 +0300 Subject: [PATCH 11/12] cargo fmt --- bign256/src/test_vectors/group.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bign256/src/test_vectors/group.rs b/bign256/src/test_vectors/group.rs index 1d0a0b03..e6fce273 100644 --- a/bign256/src/test_vectors/group.rs +++ b/bign256/src/test_vectors/group.rs @@ -100,15 +100,15 @@ pub const ADD_TEST_VECTORS: &[([u8; 32], [u8; 32])] = &[ /// Gx = 0 /// Gy = 0x6BF7FC3CFB16D69F5CE4C9A351D6835D78913966C408F6521E29CF1804516A93 /// h = 1 -/// +/// /// # Create the finite field and the elliptic curve /// F = GF(p) /// E = EllipticCurve(F, [a, b]) -/// +/// /// # Define the base point /// G = E(Gx, Gy) /// n = G.order() -/// +/// /// # Generate test vectors /// def generate_mul_test_vectors(num_vectors): /// vectors = [] @@ -117,11 +117,11 @@ pub const ADD_TEST_VECTORS: &[([u8; 32], [u8; 32])] = &[ /// P = k * G /// vectors.append((k, P)) /// return vectors -/// +/// /// # Number of test vectors to generate /// num_vectors = 20 /// test_vectors = generate_mul_test_vectors(num_vectors) -/// +/// /// # Print the test vectors in the required format /// for k, P in test_vectors: /// k_hex = f"{k:064X}" @@ -132,7 +132,7 @@ pub const ADD_TEST_VECTORS: &[([u8; 32], [u8; 32])] = &[ /// print(f' hex!("{Px_hex}"),') /// print(f' hex!("{Py_hex}"),') /// print(f' ),') -/// +/// pub const MUL_TEST_VECTORS: &[([u8; 32], [u8; 32], [u8; 32])] = &[ ( hex!("CED4907163D8C2250299A2FE6A9D4F8A676501B90D570D50999B9E17FD993DE6"), From af48289a80fc3001bb3ead999c469a0d90291214 Mon Sep 17 00:00:00 2001 From: Alexandr Kitaev Date: Sat, 27 Jul 2024 15:39:04 +0300 Subject: [PATCH 12/12] Remove snippet from doc --- bign256/src/test_vectors/group.rs | 82 +++++++++++++++---------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/bign256/src/test_vectors/group.rs b/bign256/src/test_vectors/group.rs index e6fce273..aaa3f074 100644 --- a/bign256/src/test_vectors/group.rs +++ b/bign256/src/test_vectors/group.rs @@ -89,50 +89,50 @@ pub const ADD_TEST_VECTORS: &[([u8; 32], [u8; 32])] = &[ ), ]; +// Snippet for generation: +// p = 2**256 - 189 +// a = 2**256 - 192 +// b = 0x77CE6C1515F3A8EDD2C13AABE4D8FBBE4CF55069978B9253B22E7D6BD69C03F1 +// Gx = 0 +// Gy = 0x6BF7FC3CFB16D69F5CE4C9A351D6835D78913966C408F6521E29CF1804516A93 +// h = 1 +// +// # Create the finite field and the elliptic curve +// F = GF(p) +// E = EllipticCurve(F, [a, b]) +// +// # Define the base point +// G = E(Gx, Gy) +// n = G.order() +// +// # Generate test vectors +// def generate_mul_test_vectors(num_vectors): +// vectors = [] +// for _ in range(num_vectors): +// k = ZZ.random_element(1, n) +// P = k * G +// vectors.append((k, P)) +// return vectors +// +// # Number of test vectors to generate +// num_vectors = 20 +// test_vectors = generate_mul_test_vectors(num_vectors) +// +// # Print the test vectors in the required format +// for k, P in test_vectors: +// k_hex = f"{k:064X}" +// Px_hex = f"{int(P[0]):064X}" +// Py_hex = f"{int(P[1]):064X}" +// print(f' (') +// print(f' hex!("{k_hex}"),') +// print(f' hex!("{Px_hex}"),') +// print(f' hex!("{Py_hex}"),') +// print(f' ),') + /// Scalar multiplication with the generator. /// /// These are the test vectors from sagemath snippet,that are not part of [`ADD_TEST_VECTORS`]. -/// k values is from NIST-P256 test vectors` -/// ```ignore -/// p = 2**256 - 189 -/// a = 2**256 - 192 -/// b = 0x77CE6C1515F3A8EDD2C13AABE4D8FBBE4CF55069978B9253B22E7D6BD69C03F1 -/// Gx = 0 -/// Gy = 0x6BF7FC3CFB16D69F5CE4C9A351D6835D78913966C408F6521E29CF1804516A93 -/// h = 1 -/// -/// # Create the finite field and the elliptic curve -/// F = GF(p) -/// E = EllipticCurve(F, [a, b]) -/// -/// # Define the base point -/// G = E(Gx, Gy) -/// n = G.order() -/// -/// # Generate test vectors -/// def generate_mul_test_vectors(num_vectors): -/// vectors = [] -/// for _ in range(num_vectors): -/// k = ZZ.random_element(1, n) -/// P = k * G -/// vectors.append((k, P)) -/// return vectors -/// -/// # Number of test vectors to generate -/// num_vectors = 20 -/// test_vectors = generate_mul_test_vectors(num_vectors) -/// -/// # Print the test vectors in the required format -/// for k, P in test_vectors: -/// k_hex = f"{k:064X}" -/// Px_hex = f"{int(P[0]):064X}" -/// Py_hex = f"{int(P[1]):064X}" -/// print(f' (') -/// print(f' hex!("{k_hex}"),') -/// print(f' hex!("{Px_hex}"),') -/// print(f' hex!("{Py_hex}"),') -/// print(f' ),') -/// +/// k values is generated randomly pub const MUL_TEST_VECTORS: &[([u8; 32], [u8; 32], [u8; 32])] = &[ ( hex!("CED4907163D8C2250299A2FE6A9D4F8A676501B90D570D50999B9E17FD993DE6"),