diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e3d989d..1e31d5a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,11 +13,11 @@ jobs: fail-fast: false matrix: backend_feature: - - u64_backend - - u32_backend - - p256,u64_backend + - ristretto255_u64 + - ristretto255_u32 + - p256,ristretto255_u64 frontend_feature: - - serialize + - serde toolchain: - stable - 1.51.0 @@ -57,16 +57,18 @@ jobs: # for any no_std target - thumbv6m-none-eabi backend_feature: - - u64_backend - - u32_backend - - p256,u64_backend + - + - --features ristretto255_u64 + - --features ristretto255_u32 + - --features p256 frontend_feature: - - serialize + - + - --features serde steps: - uses: actions/checkout@v2 - uses: hecrj/setup-rust-action@v1 - run: rustup target add ${{ matrix.target }} - - run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.frontend_feature }} --features ${{ matrix.backend_feature }} + - run: cargo build --verbose --target=${{ matrix.target }} --no-default-features ${{ matrix.frontend_feature }} ${{ matrix.backend_feature }} clippy: diff --git a/Cargo.toml b/Cargo.toml index 40466c7..bff254a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,37 +12,37 @@ readme = "README.md" resolver = "2" [features] -default = ["u64_backend", "serialize"] +default = ["ristretto255_u64", "serde"] +ristretto255_u64 = ["curve25519-dalek/u64_backend"] +ristretto255_u32 = ["curve25519-dalek/u32_backend"] +ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend"] +ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend"] +ristretto255_simd = ["curve25519-dalek/simd_backend"] p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"] -std = ["curve25519-dalek/std", "getrandom", "rand/std", "rand/std_rng", "num-bigint/std", "num-integer/std", "num-traits/std"] -u64_backend = ["curve25519-dalek/u64_backend"] -u32_backend = ["curve25519-dalek/u32_backend"] -simd_backend = ["curve25519-dalek/simd_backend"] -serialize = ["serde", "base64", "generic-array/serde", "curve25519-dalek/serde"] +std = [] +serde = ["serde_", "base64"] [dependencies] base64 = { version = "0.13", default-features = false, features = ["alloc"], optional = true } -curve25519-dalek = { version = "3", default-features = false } +curve25519-dalek = { version = "3", default-features = false, optional = true } digest = "0.9" displaydoc = { version = "0.2", default-features = false } generic-array = "0.14" -getrandom = { version = "0.2", optional = true } num-bigint = { version = "0.4", default-features = false, optional = true } num-integer = { version = "0.1", default-features = false, optional = true } num-traits = { version = "0.2", default-features = false, optional = true } once_cell = { version = "1", default-features = false, optional = true } p256_ = { package = "p256", version = "0.9", default-features = false, features = ["arithmetic", "zeroize"], optional = true } -rand = { version = "0.8", default-features = false } -serde = { version = "1", default-features = false, features = ["alloc", "derive"], optional = true } +rand_core = { version = "0.6", default-features = false } +serde_ = { version = "1", package = "serde", default-features = false, optional = true } subtle = { version = "2.3", default-features = false } -zeroize = { version = "1", features = ["zeroize_derive"] } - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"], optional = true } +zeroize = { version = "1", default-features = false } [dev-dependencies] +generic-array = { version = "0.14", features = ["more_lengths"] } hex = "0.4" json = "0.12" +rand = "0.8" sha2 = "0.9" regex = "1" voprf = { path = "", default-features = false, features = ["std"] } diff --git a/src/errors.rs b/src/errors.rs index c22c2a2..45a3f6a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -38,5 +38,4 @@ pub enum InternalError { } #[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl Error for InternalError {} diff --git a/src/group/expand.rs b/src/group/expand.rs index 33562a0..71da41c 100644 --- a/src/group/expand.rs +++ b/src/group/expand.rs @@ -7,9 +7,13 @@ use crate::errors::InternalError; use crate::serialization::i2osp; -use alloc::vec::Vec; +use core::ops::Add; use digest::{BlockInput, Digest}; -use generic_array::typenum::{Unsigned, U1, U2}; +use generic_array::{ + sequence::Concat, + typenum::{Unsigned, U1, U2}, + ArrayLength, GenericArray, +}; // Computes ceil(x / y) fn div_ceil(x: usize, y: usize) -> usize { @@ -17,61 +21,65 @@ fn div_ceil(x: usize, y: usize) -> usize { x / y + additive } -fn xor(x: &[u8], y: &[u8]) -> Result, InternalError> { - if x.len() != y.len() { - return Err(InternalError::HashToCurveError); - } - - Ok(x.iter().zip(y).map(|(&x1, &x2)| x1 ^ x2).collect()) +fn xor>(x: GenericArray, y: GenericArray) -> GenericArray { + x.into_iter().zip(y).map(|(x1, x2)| x1 ^ x2).collect() } /// Corresponds to the expand_message_xmd() function defined in /// -pub fn expand_message_xmd( +pub fn expand_message_xmd< + H: BlockInput + Digest, + L: ArrayLength, + D: ArrayLength + Add, +>( msg: &[u8], - dst: &[u8], - len_in_bytes: usize, -) -> Result, InternalError> { - let ell = div_ceil(len_in_bytes, ::OutputSize::USIZE); + dst: GenericArray, +) -> Result, InternalError> +where + >::Output: ArrayLength, +{ + let digest_len = ::OutputSize::USIZE; + let ell = div_ceil(L::USIZE, digest_len); if ell > 255 { return Err(InternalError::HashToCurveError); } - let dst_prime = [dst, &i2osp::(dst.len())?].concat(); + let dst_prime = dst.concat(i2osp::(D::USIZE)?); let z_pad = i2osp::<::BlockSize>(0)?; - let l_i_b_str = i2osp::(len_in_bytes)?; - let msg_prime = [ - &z_pad, - msg, - &l_i_b_str, - i2osp::(0)?.as_slice(), - &dst_prime, - ] - .concat(); - - let mut b: Vec> = alloc::vec![H::digest(&msg_prime).to_vec()]; // b[0] + let l_i_b_str = i2osp::(L::USIZE)?; + let msg_0 = i2osp::(0)?; + let msg_prime = + core::array::IntoIter::new([z_pad.as_slice(), msg, &l_i_b_str, &msg_0, &dst_prime]); let mut h = H::new(); - h.update(&b[0]); - h.update(&i2osp::(1)?); - h.update(&dst_prime); - b.push(h.finalize_reset().to_vec()); // b[1] + // b[0] + let b_0 = msg_prime + .into_iter() + .fold(&mut h, |h, msg| { + h.update(msg); + h + }) + .finalize_reset(); + let mut b_i = GenericArray::default(); - let mut uniform_bytes: Vec = Vec::new(); - uniform_bytes.extend_from_slice(&b[1]); + let mut uniform_bytes = GenericArray::default(); - for i in 2..(ell + 1) { - h.update(xor(&b[0], &b[i - 1])?); - h.update(&i2osp::(i)?); + for (i, chunk) in (1..(ell + 1)).zip(uniform_bytes.chunks_mut(digest_len)) { + h.update(xor(b_0.clone(), b_i.clone())); + h.update(i2osp::(i)?); h.update(&dst_prime); - b.push(h.finalize_reset().to_vec()); // b[i] - uniform_bytes.extend_from_slice(&b[i]); + b_i = h.finalize_reset(); + chunk.copy_from_slice(&b_i[..digest_len.min(chunk.len())]); } - Ok(uniform_bytes[..len_in_bytes].to_vec()) + Ok(uniform_bytes) } #[cfg(test)] mod tests { + use generic_array::{ + typenum::{U128, U32}, + GenericArray, + }; struct Params { msg: &'static str, @@ -180,14 +188,16 @@ mod tests { 378fba044a31f5cb44583a892f5969dcd73b3fa128816e", }, ]; - let dst = "QUUX-V01-CS02-with-expander"; + let dst = GenericArray::from(*b"QUUX-V01-CS02-with-expander"); for tv in test_vectors { - let uniform_bytes = super::expand_message_xmd::( - tv.msg.as_bytes(), - dst.as_bytes(), - tv.len_in_bytes, - ) + let uniform_bytes = match tv.len_in_bytes { + 32 => super::expand_message_xmd::(tv.msg.as_bytes(), dst) + .map(|bytes| bytes.to_vec()), + 128 => super::expand_message_xmd::(tv.msg.as_bytes(), dst) + .map(|bytes| bytes.to_vec()), + _ => unimplemented!(), + } .unwrap(); assert_eq!(tv.uniform_bytes, hex::encode(uniform_bytes)); } diff --git a/src/group/mod.rs b/src/group/mod.rs index ddfe366..e8defb6 100644 --- a/src/group/mod.rs +++ b/src/group/mod.rs @@ -7,17 +7,32 @@ //! Defines the Group trait to specify the underlying prime order group +#[cfg(any( + feature = "ristretto255_u64", + feature = "ristretto255_u32", + feature = "ristretto255_fiat_u64", + feature = "ristretto255_fiat_u32", + feature = "ristretto255_simd", + feature = "p256", +))] mod expand; #[cfg(feature = "p256")] -#[cfg_attr(docsrs, doc(cfg(feature = "p256")))] -pub(crate) mod p256; +mod p256; +#[cfg(any( + feature = "ristretto255_u64", + feature = "ristretto255_u32", + feature = "ristretto255_fiat_u64", + feature = "ristretto255_fiat_u32", + feature = "ristretto255_simd", +))] mod ristretto; use crate::errors::InternalError; use core::ops::{Add, Mul, Sub}; use digest::{BlockInput, Digest}; -use generic_array::{ArrayLength, GenericArray}; -use rand::{CryptoRng, RngCore}; +use generic_array::{typenum::U1, ArrayLength, GenericArray}; +use rand_core::{CryptoRng, RngCore}; +use subtle::ConstantTimeEq; use zeroize::Zeroize; /// A prime-order subgroup of a base field (EC, prime-order field ...). This @@ -25,6 +40,7 @@ use zeroize::Zeroize; pub trait Group: Copy + Sized + + ConstantTimeEq + for<'a> Mul<&'a ::Scalar, Output = Self> + for<'a> Add<&'a Self, Output = Self> { @@ -33,18 +49,25 @@ pub trait Group: const SUITE_ID: usize; /// transforms a password and domain separation tag (DST) into a curve point - fn hash_to_curve(msg: &[u8], dst: &[u8]) - -> Result; + fn hash_to_curve + Add>( + msg: &[u8], + dst: GenericArray, + ) -> Result + where + >::Output: ArrayLength; /// Hashes a slice of pseudo-random bytes to a scalar - fn hash_to_scalar( + fn hash_to_scalar + Add>( input: &[u8], - dst: &[u8], - ) -> Result; + dst: GenericArray, + ) -> Result + where + >::Output: ArrayLength; /// The type of base field scalars type Scalar: Zeroize + Copy + + ConstantTimeEq + for<'a> Add<&'a Self::Scalar, Output = Self::Scalar> + for<'a> Sub<&'a Self::Scalar, Output = Self::Scalar> + for<'a> Mul<&'a Self::Scalar, Output = Self::Scalar>; @@ -63,7 +86,7 @@ pub trait Group: scalar_bits: impl Into<&'a GenericArray>, ) -> Result { let scalar = Self::from_scalar_slice_unchecked(scalar_bits.into())?; - if Self::ct_equal_scalar(&scalar, &Self::scalar_zero()) { + if scalar.ct_eq(&Self::scalar_zero()).into() { return Err(InternalError::ZeroScalarError); } Ok(scalar) @@ -93,7 +116,7 @@ pub trait Group: ) -> Result { let elem = Self::from_element_slice_unchecked(element_bits.into())?; - if Self::ct_equal(&elem, &::identity()) { + if Self::ct_eq(&elem, &::identity()).into() { // found the identity element return Err(InternalError::PointError); } @@ -109,7 +132,7 @@ pub trait Group: /// Returns if the group element is equal to the identity (1) fn is_identity(&self) -> bool { - self.ct_equal(&::identity()) + self.ct_eq(&::identity()).into() } /// Returns the identity group element @@ -118,12 +141,6 @@ pub trait Group: /// Returns the scalar representing zero fn scalar_zero() -> Self::Scalar; - /// Compares in constant time if the group elements are equal - fn ct_equal(&self, other: &Self) -> bool; - - /// Compares in constant time if the scalars are equal - fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool; - /// Set the contents of self to the identity value fn zeroize(&mut self) { *self = ::identity(); diff --git a/src/group/p256.rs b/src/group/p256.rs index ee66b99..d08fee4 100644 --- a/src/group/p256.rs +++ b/src/group/p256.rs @@ -18,7 +18,7 @@ use crate::errors::InternalError; use core::ops::{Add, Div, Mul, Neg}; use core::str::FromStr; use digest::{BlockInput, Digest}; -use generic_array::typenum::{U32, U33}; +use generic_array::typenum::{Unsigned, U1, U2, U32, U33, U48}; use generic_array::{ArrayLength, GenericArray}; use num_bigint::{BigInt, Sign}; use num_integer::Integer; @@ -29,21 +29,26 @@ use p256_::elliptic_curve::group::GroupEncoding; use p256_::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint}; use p256_::elliptic_curve::Field; use p256_::{AffinePoint, EncodedPoint, ProjectivePoint}; -use rand::{CryptoRng, RngCore}; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; +use rand_core::{CryptoRng, RngCore}; +use subtle::{Choice, ConditionallySelectable}; +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.2 // `L: 48` -pub const L: usize = 48; +pub type L = U48; +#[cfg(feature = "p256")] impl Group for ProjectivePoint { const SUITE_ID: usize = 0x0003; // Implements the `hash_to_curve()` function from // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3 - fn hash_to_curve( + fn hash_to_curve + Add>( msg: &[u8], - dst: &[u8], - ) -> Result { + dst: GenericArray, + ) -> Result + where + >::Output: ArrayLength, + { // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.2 // `p: 2^256 - 2^224 + 2^192 + 2^96 - 1` const P: Lazy = Lazy::new(|| { @@ -69,11 +74,12 @@ impl Group for ProjectivePoint { // `hash_to_curve` calls `hash_to_field` with a `count` of `2` // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3 // `hash_to_field` calls `expand_message` with a `len_in_bytes` of `count * L` - let uniform_bytes = super::expand::expand_message_xmd::(msg, dst, 2 * L)?; + let uniform_bytes = + super::expand::expand_message_xmd::>::Output, _>(msg, dst)?; // hash to curve - let (q0x, q0y) = hash_to_curve_simple_swu(&uniform_bytes[..L], &A, &B, &P, &Z); - let (q1x, q1y) = hash_to_curve_simple_swu(&uniform_bytes[L..], &A, &B, &P, &Z); + let (q0x, q0y) = hash_to_curve_simple_swu(&uniform_bytes[..L::USIZE], &A, &B, &P, &Z); + let (q1x, q1y) = hash_to_curve_simple_swu(&uniform_bytes[L::USIZE..], &A, &B, &P, &Z); // convert to `p256` types let p0 = AffinePoint::from_encoded_point(&EncodedPoint::from_affine_coordinates( @@ -91,10 +97,13 @@ impl Group for ProjectivePoint { // Implements the `HashToScalar()` function from // https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.3 - fn hash_to_scalar( + fn hash_to_scalar + Add>( input: &[u8], - dst: &[u8], - ) -> Result { + dst: GenericArray, + ) -> Result + where + >::Output: ArrayLength, + { // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#[{%22num%22:211,%22gen%22:0},{%22name%22:%22XYZ%22},70,700,0] // P-256 `n` is defined as `115792089210356248762697446949407573529996955224135760342 422259061068512044369` const N: Lazy = Lazy::new(|| { @@ -106,7 +115,7 @@ impl Group for ProjectivePoint { // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3 // `HashToScalar` is `hash_to_field` - let uniform_bytes = super::expand::expand_message_xmd::(input, dst, L)?; + let uniform_bytes = super::expand::expand_message_xmd::(input, dst)?; let bytes = BigInt::from_bytes_be(Sign::Plus, &uniform_bytes) .mod_floor(&N) .to_bytes_be() @@ -164,14 +173,6 @@ impl Group for ProjectivePoint { fn scalar_zero() -> Self::Scalar { Self::Scalar::zero() } - - fn ct_equal(&self, other: &Self) -> bool { - self.ct_eq(other).into() - } - - fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool { - s1.ct_eq(s2).into() - } } /// Corresponds to the hash_to_curve_simple_swu() function defined in @@ -431,6 +432,7 @@ fn hash_to_curve_simple_swu>( #[cfg(test)] mod tests { use super::*; + use generic_array::typenum::U96; struct Params { msg: &'static str, @@ -531,13 +533,12 @@ mod tests { q1y: "f6ed88a7aab56a488100e6f1174fa9810b47db13e86be999644922961206e184", }, ]; - let dst = "QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_"; + let dst = GenericArray::from(*b"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_"); for tv in test_vectors { - let uniform_bytes = super::super::expand::expand_message_xmd::( + let uniform_bytes = super::super::expand::expand_message_xmd::( tv.msg.as_bytes(), - dst.as_bytes(), - 96, + dst, ) .unwrap(); diff --git a/src/group/ristretto.rs b/src/group/ristretto.rs index ea416bd..70fd83b 100644 --- a/src/group/ristretto.rs +++ b/src/group/ristretto.rs @@ -8,6 +8,7 @@ use super::Group; use crate::errors::InternalError; use core::convert::TryInto; +use core::ops::Add; use curve25519_dalek::{ constants::RISTRETTO_BASEPOINT_POINT, ristretto::{CompressedRistretto, RistrettoPoint}, @@ -15,21 +16,33 @@ use curve25519_dalek::{ traits::Identity, }; use digest::{BlockInput, Digest}; -use generic_array::{typenum::U32, GenericArray}; -use rand::{CryptoRng, RngCore}; -use subtle::ConstantTimeEq; +use generic_array::{ + typenum::{U1, U32, U64}, + ArrayLength, GenericArray, +}; +use rand_core::{CryptoRng, RngCore}; /// The implementation of such a subgroup for Ristretto +#[cfg(any( + feature = "ristretto255_u64", + feature = "ristretto255_u32", + feature = "ristretto255_fiat_u64", + feature = "ristretto255_fiat_u32", + feature = "ristretto255_simd", +))] impl Group for RistrettoPoint { const SUITE_ID: usize = 0x0001; // Implements the `hash_to_ristretto255()` function from // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt - fn hash_to_curve( + fn hash_to_curve + Add>( msg: &[u8], - dst: &[u8], - ) -> Result { - let uniform_bytes = super::expand::expand_message_xmd::(msg, dst, 64)?; + dst: GenericArray, + ) -> Result + where + >::Output: ArrayLength, + { + let uniform_bytes = super::expand::expand_message_xmd::(msg, dst)?; Ok(RistrettoPoint::from_uniform_bytes( uniform_bytes @@ -41,11 +54,14 @@ impl Group for RistrettoPoint { // Implements the `HashToScalar()` function from // https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.1 - fn hash_to_scalar( + fn hash_to_scalar + Add>( input: &[u8], - dst: &[u8], - ) -> Result { - let uniform_bytes = super::expand::expand_message_xmd::(input, dst, 64)?; + dst: GenericArray, + ) -> Result + where + >::Output: ArrayLength, + { + let uniform_bytes = super::expand::expand_message_xmd::(input, dst)?; Ok(Scalar::from_bytes_mod_order_wide( uniform_bytes @@ -121,12 +137,4 @@ impl Group for RistrettoPoint { fn scalar_zero() -> Self::Scalar { Self::Scalar::zero() } - - fn ct_equal(&self, other: &Self) -> bool { - ConstantTimeEq::ct_eq(self, other).into() - } - - fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool { - ConstantTimeEq::ct_eq(s1, s2).into() - } } diff --git a/src/impls.rs b/src/impls.rs index a04311e..f3635d3 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -118,12 +118,11 @@ macro_rules! impl_traits_for { } } - #[cfg(feature = "serialize")] - #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] - impl$(<$($gen$(: $bound1 $(+ $bound2)*)?),+>)? serde::Serialize for $name$(<$($gen),+>)? { + #[cfg(feature = "serde")] + impl$(<$($gen$(: $bound1 $(+ $bound2)*)?),+>)? serde_::Serialize for $name$(<$($gen),+>)? { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: serde_::Serializer, { if serializer.is_human_readable() { serializer.serialize_str(&base64::encode(&self.serialize())) @@ -133,14 +132,13 @@ macro_rules! impl_traits_for { } } - #[cfg(feature = "serialize")] - #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] - impl<'de, $($($gen$(: $bound1 $(+ $bound2)*)?),+)?> serde::Deserialize<'de> for $name$(<$($gen),+>)? { + #[cfg(feature = "serde")] + impl<'de, $($($gen$(: $bound1 $(+ $bound2)*)?),+)?> serde_::Deserialize<'de> for $name$(<$($gen),+>)? { fn deserialize(deserializer: D) -> Result where - D: serde::Deserializer<'de>, + D: serde_::Deserializer<'de>, { - use serde::de::Error; + use serde_::de::Error; if deserializer.is_human_readable() { let s = <&str>::deserialize(deserializer)?; diff --git a/src/lib.rs b/src/lib.rs index f85d7f0..e41d7f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -398,16 +398,17 @@ //! - The `p256` feature enables using p256 as the underlying group for the [Group](group::Group) choice. //! Note that this is currently an experimental feature ⚠️, and is not yet ready for production use. //! -//! - The `serialize` feature, enabled by default, provides convenience functions for serializing and deserializing with +//! - The `serde` feature, enabled by default, provides convenience functions for serializing and deserializing with //! [serde](https://serde.rs/). //! -//! - The `u32_backend` and `u64_backend` features are re-exported from +//! - The backend features are re-exported from //! [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) and allow for selecting -//! the corresponding backend for the curve arithmetic used. The `u64_backend` feature is included as the default. +//! the corresponding backend for the curve arithmetic used. The `ristretto255_u64` feature is included as the default. +//! Other features are mapped as `ristretto255_u32`, `ristretto255_fiat_u64` and `ristretto255_fiat_u32`. //! -//! - The `simd_backend` feature is re-exported from +//! - The `ristretto255_simd` feature is re-exported from //! [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) and enables parallel formulas, -//! using either AVX2 or AVX512-IFMA. This will automatically enable the `u64_backend` and requires Rust nightly. +//! using either AVX2 or AVX512-IFMA. This will automatically enable the `ristretto255_u64` and requires Rust nightly. #![deny(unsafe_code)] #![warn(clippy::cargo, missing_docs)] @@ -429,8 +430,6 @@ mod tests; // Exports -pub use rand; - pub use crate::voprf::{ BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableClientBlindResult, NonVerifiableServer, NonVerifiableServerEvaluateResult, VerifiableClient, diff --git a/src/tests/mock_rng.rs b/src/tests/mock_rng.rs index 9f58b37..fc80938 100644 --- a/src/tests/mock_rng.rs +++ b/src/tests/mock_rng.rs @@ -7,7 +7,7 @@ use alloc::vec::Vec; use core::cmp::min; -use rand::{CryptoRng, Error, RngCore}; +use rand_core::{CryptoRng, Error, RngCore}; /// A simple implementation of `RngCore` for testing purposes. /// diff --git a/src/voprf.rs b/src/voprf.rs index 79e0423..848410c 100644 --- a/src/voprf.rs +++ b/src/voprf.rs @@ -21,7 +21,8 @@ use generic_array::{ typenum::{U1, U11, U2}, GenericArray, }; -use rand::{CryptoRng, RngCore}; +use rand_core::{CryptoRng, RngCore}; +use subtle::ConstantTimeEq; /////////////// // Constants // @@ -366,7 +367,7 @@ impl NonVerifiableServer { pub fn new_from_seed(seed: &[u8]) -> Result { let dst = GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::(Mode::Base)?); - let sk = G::hash_to_scalar::(seed, &dst)?; + let sk = G::hash_to_scalar::(seed, dst)?; Ok(Self { sk, hash: PhantomData, @@ -394,7 +395,7 @@ impl NonVerifiableServer { .concat(); let dst = GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::(Mode::Base)?); - let m = G::hash_to_scalar::(&context, &dst)?; + let m = G::hash_to_scalar::(&context, dst)?; let t = self.sk + &m; let evaluation_element = blinded_element.value * &G::scalar_invert(&t); Ok(NonVerifiableServerEvaluateResult { @@ -439,7 +440,7 @@ impl VerifiableServer { pub fn new_from_seed(seed: &[u8]) -> Result { let dst = GenericArray::from(*STR_HASH_TO_SCALAR) .concat(get_context_string::(Mode::Verifiable)?); - let sk = G::hash_to_scalar::(seed, &dst)?; + let sk = G::hash_to_scalar::(seed, dst)?; let pk = G::base_point() * &sk; Ok(Self { sk, @@ -490,7 +491,7 @@ impl VerifiableServer { .concat(); let dst = GenericArray::from(*STR_HASH_TO_SCALAR) .concat(get_context_string::(Mode::Verifiable)?); - let m = G::hash_to_scalar::(&context, &dst)?; + let m = G::hash_to_scalar::(&context, dst)?; let t = self.sk + &m; let evaluation_elements: Vec> = blinded_elements .into_iter() @@ -640,7 +641,7 @@ fn blind( // Choose a random scalar that must be non-zero let blind = ::random_nonzero_scalar(blinding_factor_rng); let dst = GenericArray::from(*STR_HASH_TO_GROUP).concat(get_context_string::(mode)?); - let hashed_point = ::hash_to_curve::(input, &dst)?; + let hashed_point = ::hash_to_curve::(input, dst)?; let blinded_element = hashed_point * &blind; Ok((blind, blinded_element)) } @@ -664,7 +665,7 @@ where let dst = GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::(Mode::Verifiable)?); - let m = G::hash_to_scalar::(&context, &dst)?; + let m = G::hash_to_scalar::(&context, dst)?; let g = G::base_point(); let t = g * &m; @@ -713,7 +714,7 @@ fn generate_proof( let hash_to_scalar_dst = GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::(Mode::Verifiable)?); - let c_scalar = G::hash_to_scalar::(&h2_input, &hash_to_scalar_dst)?; + let c_scalar = G::hash_to_scalar::(&h2_input, hash_to_scalar_dst)?; let s_scalar = r - &(c_scalar * &k); Ok(Proof { @@ -749,9 +750,9 @@ fn verify_proof( let hash_to_scalar_dst = GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::(Mode::Verifiable)?); - let c = G::hash_to_scalar::(&h2_input, &hash_to_scalar_dst)?; + let c = G::hash_to_scalar::(&h2_input, hash_to_scalar_dst)?; - match G::ct_equal_scalar(&c, &proof.c_scalar) { + match c.ct_eq(&proof.c_scalar).into() { true => Ok(()), false => Err(InternalError::ProofVerificationError), } @@ -815,7 +816,7 @@ fn compute_composites( .concat(); let dst = GenericArray::from(*STR_HASH_TO_SCALAR) .concat(get_context_string::(Mode::Verifiable)?); - let di = G::hash_to_scalar::(&h2_input, &dst)?; + let di = G::hash_to_scalar::(&h2_input, dst)?; m = c.value * &di + &m; z = match k_option { Some(_) => z, @@ -860,7 +861,7 @@ mod tests { ) -> GenericArray::OutputSize> { let dst = GenericArray::from(*STR_HASH_TO_GROUP).concat(get_context_string::(mode).unwrap()); - let point = G::hash_to_curve::(input, &dst).unwrap(); + let point = G::hash_to_curve::(input, dst).unwrap(); let context = [ STR_CONTEXT, @@ -870,7 +871,7 @@ mod tests { .concat(); let dst = GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::(mode).unwrap()); - let m = ::hash_to_scalar::(&context, &dst).unwrap(); + let m = ::hash_to_scalar::(&context, dst).unwrap(); let res = point * &::scalar_invert(&(key + &m)); @@ -931,7 +932,7 @@ mod tests { .unwrap(); let wrong_pk = { // Choose a group element that is unlikely to be the right public key - G::hash_to_curve::(b"msg", b"dst").unwrap() + G::hash_to_curve::(b"msg", (*b"dst").into()).unwrap() }; let client_finalize_result = client_blind_result.state.finalize( server_result.message, @@ -1000,7 +1001,7 @@ mod tests { .unwrap(); let wrong_pk = { // Choose a group element that is unlikely to be the right public key - G::hash_to_curve::(b"msg", b"dst").unwrap() + G::hash_to_curve::(b"msg", (*b"dst").into()).unwrap() }; let client_finalize_result = VerifiableClient::batch_finalize( &client_states, @@ -1032,7 +1033,7 @@ mod tests { let dst = GenericArray::from(*STR_HASH_TO_GROUP) .concat(get_context_string::(Mode::Base).unwrap()); - let point = G::hash_to_curve::(&input, &dst).unwrap(); + let point = G::hash_to_curve::(&input, dst).unwrap(); let res2 = finalize_after_unblind::( Some((input.as_slice(), point)).into_iter(), info,