diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3e4e8d6..279025a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,8 +37,7 @@ jobs: backend_feature: - ristretto255_u64 - ristretto255_u32 - # skip doc tests - - p256 --lib + - p256 - ristretto255_u64,p256 frontend_feature: - diff --git a/Cargo.toml b/Cargo.toml index 106744c..d7782b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,12 @@ version = "0.3.0" danger = [] default = ["ristretto255_u64", "serde"] p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"] -ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend"] -ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend"] -ristretto255_simd = ["curve25519-dalek/simd_backend"] -ristretto255_u32 = ["curve25519-dalek/u32_backend"] -ristretto255_u64 = ["curve25519-dalek/u64_backend"] +ristretto255 = [] +ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend", "ristretto255"] +ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend", "ristretto255"] +ristretto255_simd = ["curve25519-dalek/simd_backend", "ristretto255"] +ristretto255_u32 = ["curve25519-dalek/u32_backend", "ristretto255"] +ristretto255_u64 = ["curve25519-dalek/u64_backend", "ristretto255"] std = [] [dependencies] diff --git a/src/group/mod.rs b/src/group/mod.rs index 72761bb..890bcaa 100644 --- a/src/group/mod.rs +++ b/src/group/mod.rs @@ -7,20 +7,12 @@ //! 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", -))] +#[cfg(any(feature = "ristretto255", feature = "p256",))] mod expand; #[cfg(feature = "p256")] mod p256; -cfg_ristretto! { - mod ristretto; -} +#[cfg(feature = "ristretto255")] +mod ristretto; use core::ops::{Add, Mul, Sub}; diff --git a/src/group/ristretto.rs b/src/group/ristretto.rs index 45edf2c..a58902a 100644 --- a/src/group/ristretto.rs +++ b/src/group/ristretto.rs @@ -5,127 +5,123 @@ // License, Version 2.0 found in the LICENSE-APACHE file in the root directory // of this source tree. -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}, - scalar::Scalar, - traits::Identity, -}; + +use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; +use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; +use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::traits::Identity; use digest::{BlockInput, Digest}; -use generic_array::{ - typenum::{U1, U32, U64}, - ArrayLength, GenericArray, -}; +use generic_array::typenum::{U1, U32, U64}; +use generic_array::{ArrayLength, GenericArray}; use rand_core::{CryptoRng, RngCore}; -// `cfg` here is only needed because of a bug in Rust's crate feature documentation. See: -// https://github.com/rust-lang/rust/issues/83428 -cfg_ristretto! { - /// The implementation of such a subgroup for Ristretto - impl Group for RistrettoPoint { - const SUITE_ID: usize = 0x0001; +use super::Group; +use crate::errors::InternalError; - // 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 + Add>( - msg: &[u8], - dst: GenericArray, - ) -> Result - where - >::Output: ArrayLength, - { - let uniform_bytes = super::expand::expand_message_xmd::(Some(msg), dst)?; +// `cfg` here is only needed because of a bug in Rust's crate feature documentation. See: https://github.com/rust-lang/rust/issues/83428 +#[cfg(feature = "ristretto255")] +/// The implementation of such a subgroup for Ristretto +impl Group for RistrettoPoint { + const SUITE_ID: usize = 0x0001; - Ok(RistrettoPoint::from_uniform_bytes( - uniform_bytes - .as_slice() - .try_into() - .map_err(|_| InternalError::HashToCurveError)?, - )) - } + // 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 + Add>( + msg: &[u8], + dst: GenericArray, + ) -> Result + where + >::Output: ArrayLength, + { + let uniform_bytes = super::expand::expand_message_xmd::(Some(msg), dst)?; - // Implements the `HashToScalar()` function from - // https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.1 - fn hash_to_scalar< - 'a, - H: BlockInput + Digest, - D: ArrayLength + Add, - I: IntoIterator, - >( - input: I, - dst: GenericArray, - ) -> Result - where - >::Output: ArrayLength, - { - let uniform_bytes = super::expand::expand_message_xmd::(input, dst)?; + Ok(RistrettoPoint::from_uniform_bytes( + uniform_bytes + .as_slice() + .try_into() + .map_err(|_| InternalError::HashToCurveError)?, + )) + } - Ok(Scalar::from_bytes_mod_order_wide( - uniform_bytes - .as_slice() - .try_into() - .map_err(|_| InternalError::HashToCurveError)?, - )) - } + // Implements the `HashToScalar()` function from + // https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.1 + fn hash_to_scalar< + 'a, + H: BlockInput + Digest, + D: ArrayLength + Add, + I: IntoIterator, + >( + input: I, + dst: GenericArray, + ) -> Result + where + >::Output: ArrayLength, + { + let uniform_bytes = super::expand::expand_message_xmd::(input, dst)?; - type Scalar = Scalar; - type ScalarLen = U32; - fn from_scalar_slice_unchecked( - scalar_bits: &GenericArray, - ) -> Result { - Ok(Scalar::from_bytes_mod_order(*scalar_bits.as_ref())) - } + Ok(Scalar::from_bytes_mod_order_wide( + uniform_bytes + .as_slice() + .try_into() + .map_err(|_| InternalError::HashToCurveError)?, + )) + } - fn random_nonzero_scalar(rng: &mut R) -> Self::Scalar { - loop { - let scalar = { - let mut scalar_bytes = [0u8; 64]; - rng.fill_bytes(&mut scalar_bytes); - Scalar::from_bytes_mod_order_wide(&scalar_bytes) - }; + type Scalar = Scalar; + type ScalarLen = U32; + fn from_scalar_slice_unchecked( + scalar_bits: &GenericArray, + ) -> Result { + Ok(Scalar::from_bytes_mod_order(*scalar_bits.as_ref())) + } - if scalar != Scalar::zero() { - break scalar; - } + fn random_nonzero_scalar(rng: &mut R) -> Self::Scalar { + loop { + let scalar = { + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Scalar::from_bytes_mod_order_wide(&scalar_bytes) + }; + + if scalar != Scalar::zero() { + break scalar; } } + } - fn scalar_as_bytes(scalar: Self::Scalar) -> GenericArray { - scalar.to_bytes().into() - } + fn scalar_as_bytes(scalar: Self::Scalar) -> GenericArray { + scalar.to_bytes().into() + } - fn scalar_invert(scalar: &Self::Scalar) -> Self::Scalar { - scalar.invert() - } + fn scalar_invert(scalar: &Self::Scalar) -> Self::Scalar { + scalar.invert() + } - // The byte length necessary to represent group elements - type ElemLen = U32; - fn from_element_slice_unchecked( - element_bits: &GenericArray, - ) -> Result { - CompressedRistretto::from_slice(element_bits) - .decompress() - .ok_or(InternalError::PointError) - } - // serialization of a group element - fn to_arr(&self) -> GenericArray { - self.compress().to_bytes().into() - } + // The byte length necessary to represent group elements + type ElemLen = U32; + fn from_element_slice_unchecked( + element_bits: &GenericArray, + ) -> Result { + CompressedRistretto::from_slice(element_bits) + .decompress() + .ok_or(InternalError::PointError) + } + // serialization of a group element + fn to_arr(&self) -> GenericArray { + self.compress().to_bytes().into() + } - fn base_point() -> Self { - RISTRETTO_BASEPOINT_POINT - } + fn base_point() -> Self { + RISTRETTO_BASEPOINT_POINT + } - fn identity() -> Self { - ::identity() - } + fn identity() -> Self { + ::identity() + } - fn scalar_zero() -> Self::Scalar { - Self::Scalar::zero() - } + fn scalar_zero() -> Self::Scalar { + Self::Scalar::zero() } } diff --git a/src/group/tests.rs b/src/group/tests.rs index 2d04156..1a8a980 100644 --- a/src/group/tests.rs +++ b/src/group/tests.rs @@ -15,12 +15,13 @@ use crate::group::Group; #[test] fn test_group_properties() -> Result<(), InternalError> { - cfg_ristretto! { { + #[cfg(feature = "ristretto255")] + { use curve25519_dalek::ristretto::RistrettoPoint; test_identity_element_error::()?; test_zero_scalar_error::()?; - } } + } #[cfg(feature = "p256")] { diff --git a/src/lib.rs b/src/lib.rs index a65323d..a6d6830 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ //! //! We will use the following choices in this example: //! -//! ``` +//! ```ignore //! type Group = curve25519_dalek::ristretto::RistrettoPoint; //! type Hash = sha2::Sha512; //! ``` @@ -51,8 +51,14 @@ //! must be persisted on the server and used for online client evaluations. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! use rand::rngs::OsRng; //! use rand::RngCore; //! use voprf::NonVerifiableServer; @@ -71,8 +77,14 @@ //! step of the VOPRF protocol. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! use rand::rngs::OsRng; //! use rand::RngCore; //! use voprf::NonVerifiableClient; @@ -92,8 +104,14 @@ //! [EvaluationElement] to be sent to the client. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! # use voprf::NonVerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -118,8 +136,14 @@ //! [NonVerifiableClient::finalize] to produce an output for the protocol. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! # use voprf::NonVerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -163,8 +187,14 @@ //! must be persisted on the server and used for online client evaluations. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! use rand::rngs::OsRng; //! use rand::RngCore; //! use voprf::VerifiableServer; @@ -190,8 +220,14 @@ //! of the VOPRF protocol. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! use rand::rngs::OsRng; //! use rand::RngCore; //! use voprf::VerifiableClient; @@ -211,8 +247,14 @@ //! a proof. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -238,8 +280,14 @@ //! output for the protocol. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -288,8 +336,14 @@ //! messages: //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -311,8 +365,14 @@ //! proof: //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -342,8 +402,14 @@ //! outputs if the proof verifies correctly. //! //! ``` +//! # #[cfg(feature = "ristretto255")] //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # #[cfg(feature = "ristretto255")] //! # type Hash = sha2::Sha512; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Group = p256_::ProjectivePoint; +//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))] +//! # type Hash = sha2::Sha256; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -411,7 +477,9 @@ //! and allow for selecting 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`. +//! `ristretto255_fiat_u32`. Any `ristretto255_*` backend feature will enable +//! the `ristretto255` feature, which can be used too, but keep in mind that +//! `curve25519-dalek` will fail to compile without a selected backend. //! //! - 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 diff --git a/src/tests/voprf_test_vectors.rs b/src/tests/voprf_test_vectors.rs index 2c065ac..d75fddc 100644 --- a/src/tests/voprf_test_vectors.rs +++ b/src/tests/voprf_test_vectors.rs @@ -87,7 +87,8 @@ fn test_vectors() -> Result<(), InternalError> { let rfc = json::parse(rfc_to_json(super::voprf_vectors::VECTORS).as_str()) .expect("Could not parse json"); - cfg_ristretto! { { + #[cfg(feature = "ristretto255")] + { use curve25519_dalek::ristretto::RistrettoPoint; use sha2::Sha512; @@ -112,7 +113,7 @@ fn test_vectors() -> Result<(), InternalError> { test_verifiable_blind::(&ristretto_verifiable_tvs)?; test_verifiable_evaluate::(&ristretto_verifiable_tvs)?; test_verifiable_finalize::(&ristretto_verifiable_tvs)?; - } } + } #[cfg(feature = "p256")] { diff --git a/src/util.rs b/src/util.rs index 610b1e9..94106e9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -121,29 +121,6 @@ macro_rules! chain { }; } -macro_rules! cfg_ristretto { - ($tree:tt) => { - #[cfg(any( - feature = "ristretto255_u64", - feature = "ristretto255_u32", - feature = "ristretto255_fiat_u64", - feature = "ristretto255_fiat_u32", - feature = "ristretto255_simd", - ))] - $tree - }; - ($($item:item)+) => { - $(#[cfg(any( - feature = "ristretto255_u64", - feature = "ristretto255_u32", - feature = "ristretto255_fiat_u64", - feature = "ristretto255_fiat_u32", - feature = "ristretto255_simd", - ))] - $item)+ - }; -} - #[cfg(test)] mod unit_tests { use generic_array::typenum::{U1, U2}; @@ -172,9 +149,13 @@ mod unit_tests { macro_rules! test_deserialize { ($item:ident, $bytes:ident) => { - cfg_ristretto! { { - let _ = $item::::deserialize(&$bytes[..]); - } } + #[cfg(feature = "ristretto255")] + { + let _ = + $item::::deserialize( + &$bytes[..], + ); + } #[cfg(feature = "p256")] { let _ = $item::::deserialize(&$bytes[..]); diff --git a/src/voprf.rs b/src/voprf.rs index 1c8c81f..92dba94 100644 --- a/src/voprf.rs +++ b/src/voprf.rs @@ -1196,7 +1196,8 @@ mod tests { #[test] fn test_functionality() -> Result<(), InternalError> { - cfg_ristretto! { { + #[cfg(feature = "ristretto255")] + { use curve25519_dalek::ristretto::RistrettoPoint; use sha2::Sha512; @@ -1211,7 +1212,7 @@ mod tests { zeroize_base_server::(); zeroize_verifiable_client::(); zeroize_verifiable_server::(); - } } + } #[cfg(feature = "p256")] {