diff --git a/src/ciphersuite.rs b/src/ciphersuite.rs deleted file mode 100644 index 7dd2b6e..0000000 --- a/src/ciphersuite.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache -// License, Version 2.0 found in the LICENSE-APACHE file in the root directory -// of this source tree. - -//! Defines the CipherSuite trait to specify the underlying primitives for VOPRF - -/// Configures the underlying primitives used in VOPRF -pub trait CipherSuite { - /// A finite cyclic group along with a point representation that allows some - /// customization on how to hash an input to a curve point. See `group::Group`. - type Group: crate::group::Group; - /// The main hash function to use (for HKDF computations and hashing transcripts). - type Hash: crate::hash::Hash; -} diff --git a/src/group/expand.rs b/src/group/expand.rs index 4a1c0f0..fe1f2ad 100644 --- a/src/group/expand.rs +++ b/src/group/expand.rs @@ -6,7 +6,6 @@ // of this source tree. use crate::errors::InternalError; -use crate::hash::Hash; use crate::serialization::i2osp; use alloc::vec::Vec; use digest::{BlockInput, Digest}; @@ -28,7 +27,7 @@ fn xor(x: &[u8], y: &[u8]) -> Result, InternalError> { /// Corresponds to the expand_message_xmd() function defined in /// -pub fn expand_message_xmd( +pub fn expand_message_xmd( msg: &[u8], dst: &[u8], len_in_bytes: usize, diff --git a/src/group/mod.rs b/src/group/mod.rs index 706a7f7..5390760 100644 --- a/src/group/mod.rs +++ b/src/group/mod.rs @@ -14,8 +14,8 @@ pub(crate) mod p256; mod ristretto; use crate::errors::InternalError; -use crate::hash::Hash; use core::ops::{Add, Mul, Sub}; +use digest::{BlockInput, Digest}; use generic_array::{ArrayLength, GenericArray}; use rand::{CryptoRng, RngCore}; use zeroize::Zeroize; @@ -33,10 +33,14 @@ 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(msg: &[u8], dst: &[u8]) + -> Result; /// Hashes a slice of pseudo-random bytes to a scalar - fn hash_to_scalar(input: &[u8], dst: &[u8]) -> Result; + fn hash_to_scalar( + input: &[u8], + dst: &[u8], + ) -> Result; /// The type of base field scalars type Scalar: Zeroize diff --git a/src/group/p256.rs b/src/group/p256.rs index a1aa16d..109091b 100644 --- a/src/group/p256.rs +++ b/src/group/p256.rs @@ -15,9 +15,9 @@ use super::Group; use crate::errors::InternalError; -use crate::hash::Hash; use core::ops::{Add, Div, Mul, Neg}; use core::str::FromStr; +use digest::{BlockInput, Digest}; use generic_array::typenum::{U32, U33}; use generic_array::{ArrayLength, GenericArray}; use num_bigint::{BigInt, Sign}; @@ -41,7 +41,10 @@ impl Group for ProjectivePoint { // 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(msg: &[u8], dst: &[u8]) -> Result { + fn hash_to_curve( + msg: &[u8], + dst: &[u8], + ) -> Result { // 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(|| { @@ -89,7 +92,10 @@ 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(input: &[u8], dst: &[u8]) -> Result { + fn hash_to_scalar( + input: &[u8], + dst: &[u8], + ) -> Result { // 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(|| { diff --git a/src/group/ristretto.rs b/src/group/ristretto.rs index 457bb75..ea416bd 100644 --- a/src/group/ristretto.rs +++ b/src/group/ristretto.rs @@ -7,7 +7,6 @@ use super::Group; use crate::errors::InternalError; -use crate::hash::Hash; use core::convert::TryInto; use curve25519_dalek::{ constants::RISTRETTO_BASEPOINT_POINT, @@ -15,6 +14,7 @@ use curve25519_dalek::{ scalar::Scalar, traits::Identity, }; +use digest::{BlockInput, Digest}; use generic_array::{typenum::U32, GenericArray}; use rand::{CryptoRng, RngCore}; use subtle::ConstantTimeEq; @@ -25,7 +25,10 @@ impl Group for RistrettoPoint { // 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(msg: &[u8], dst: &[u8]) -> Result { + fn hash_to_curve( + msg: &[u8], + dst: &[u8], + ) -> Result { let uniform_bytes = super::expand::expand_message_xmd::(msg, dst, 64)?; Ok(RistrettoPoint::from_uniform_bytes( @@ -38,7 +41,10 @@ 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(input: &[u8], dst: &[u8]) -> Result { + fn hash_to_scalar( + input: &[u8], + dst: &[u8], + ) -> Result { let uniform_bytes = super::expand::expand_message_xmd::(input, dst, 64)?; Ok(Scalar::from_bytes_mod_order_wide( diff --git a/src/group/tests.rs b/src/group/tests.rs index 5a130a3..cc40146 100644 --- a/src/group/tests.rs +++ b/src/group/tests.rs @@ -9,42 +9,41 @@ use crate::errors::InternalError; use crate::group::Group; -use crate::CipherSuite; // Test that the deserialization of a group element should throw an error // if the identity element can be deserialized properly #[test] fn test_group_properties() -> Result<(), InternalError> { - use crate::tests::Ristretto255Sha512; + use curve25519_dalek::ristretto::RistrettoPoint; - test_identity_element_error::()?; - test_zero_scalar_error::()?; + test_identity_element_error::()?; + test_zero_scalar_error::()?; #[cfg(feature = "p256")] { - use crate::tests::P256Sha256; + use p256_::ProjectivePoint; - test_identity_element_error::()?; - test_zero_scalar_error::()?; + test_identity_element_error::()?; + test_zero_scalar_error::()?; } Ok(()) } // Checks that the identity element cannot be deserialized -fn test_identity_element_error() -> Result<(), InternalError> { - let identity = CS::Group::identity(); - let result = CS::Group::from_element_slice(&identity.to_arr()); +fn test_identity_element_error() -> Result<(), InternalError> { + let identity = G::identity(); + let result = G::from_element_slice(&identity.to_arr()); assert!(matches!(result, Err(InternalError::PointError))); Ok(()) } // Checks that the zero scalar cannot be deserialized -fn test_zero_scalar_error() -> Result<(), InternalError> { - let zero_scalar = CS::Group::scalar_zero(); - let result = CS::Group::from_scalar_slice(&CS::Group::scalar_as_bytes(zero_scalar)); +fn test_zero_scalar_error() -> Result<(), InternalError> { + let zero_scalar = G::scalar_zero(); + let result = G::from_scalar_slice(&G::scalar_as_bytes(zero_scalar)); assert!(matches!(result, Err(InternalError::ZeroScalarError))); Ok(()) diff --git a/src/hash.rs b/src/hash.rs deleted file mode 100644 index 87161f2..0000000 --- a/src/hash.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache -// License, Version 2.0 found in the LICENSE-APACHE file in the root directory -// of this source tree. - -//! A convenience trait for digest bounds used throughout the library - -use digest::{BlockInput, FixedOutput, Reset, Update}; - -/// Trait inheriting the requirements from digest::Digest for compatibility with HKDF and HMAC -// Associated types could be simplified when they are made as defaults: -// https://github.com/rust-lang/rust/issues/29661 -pub trait Hash: Update + BlockInput + FixedOutput + Reset + Default + Clone {} - -impl Hash for T {} diff --git a/src/impls.rs b/src/impls.rs index 2545acf..1580798 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -6,8 +6,8 @@ // of this source tree. macro_rules! impl_debug_eq_hash_for { - (struct $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { - impl$(<$($gen$(: $bound)?),+>)? core::fmt::Debug for $name$(<$($gen),+>)? + (struct $name:ident$(<$($gen:ident$(: $bound1:tt$( + $bound2:tt)*)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { + impl$(<$($gen$(: $bound1$( + $bound2)*)?),+>)? core::fmt::Debug for $name$(<$($gen),+>)? $(where $($type: core::fmt::Debug,)+)? { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -18,11 +18,11 @@ macro_rules! impl_debug_eq_hash_for { } } - impl$(<$($gen$(: $bound)?),+>)? Eq for $name$(<$($gen),+>)? + impl$(<$($gen$(: $bound1$( + $bound2)*)?),+>)? Eq for $name$(<$($gen),+>)? $(where $($type: Eq,)+)? {} - impl$(<$($gen$(: $bound)?),+>)? PartialEq for $name$(<$($gen),+>)? + impl$(<$($gen$(: $bound1$( + $bound2)*)?),+>)? PartialEq for $name$(<$($gen),+>)? $(where $($type: PartialEq,)+)? { fn eq(&self, other: &Self) -> bool { @@ -31,17 +31,17 @@ macro_rules! impl_debug_eq_hash_for { } } - impl$(<$($gen$(: $bound)?),+>)? core::hash::Hash for $name$(<$($gen),+>)? + impl$(<$($gen$(: $bound1$( + $bound2)*)?),+>)? core::hash::Hash for $name$(<$($gen),+>)? $(where $($type: core::hash::Hash,)+)? { - fn hash(&self, state: &mut H) { + fn hash<_H: core::hash::Hasher>(&self, state: &mut _H) { core::hash::Hash::hash(&self.$field1, state); $(core::hash::Hash::hash(&self.$field2, state);)* } } }; - (tuple $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:tt$(, $field2:tt)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { - impl$(<$($gen$(: $bound)?),+>)? core::fmt::Debug for $name$(<$($gen),+>)? + (tuple $name:ident$(<$($gen:ident$(: $bound1:tt$( + $bound2:tt)*)?),+$(,)?>)?, [$field1:tt$(, $field2:tt)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? core::fmt::Debug for $name$(<$($gen),+>)? $(where $($type: core::fmt::Debug,)+)? { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -52,11 +52,11 @@ macro_rules! impl_debug_eq_hash_for { } } - impl$(<$($gen$(: $bound)?),+>)? Eq for $name$(<$($gen),+>)? + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? Eq for $name$(<$($gen),+>)? $(where $($type: Eq,)+)? {} - impl$(<$($gen$(: $bound)?),+>)? PartialEq for $name$(<$($gen),+>)? + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? PartialEq for $name$(<$($gen),+>)? $(where $($type: PartialEq,)+)? { fn eq(&self, other: &Self) -> bool { @@ -65,7 +65,7 @@ macro_rules! impl_debug_eq_hash_for { } } - impl$(<$($gen$(: $bound)?),+>)? core::hash::Hash for $name$(<$($gen),+>)? + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? core::hash::Hash for $name$(<$($gen),+>)? $(where $($type: core::hash::Hash,)+)? { fn hash(&self, state: &mut H) { @@ -77,8 +77,8 @@ macro_rules! impl_debug_eq_hash_for { } macro_rules! impl_clone_for { - (struct $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { - impl$(<$($gen$(: $bound)?),+>)? Clone for $name$(<$($gen),+>)? + (struct $name:ident$(<$($gen:ident$(: $bound1:tt$( + $bound2:tt)*)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? Clone for $name$(<$($gen),+>)? $(where $($type: Clone,)+)? { fn clone(&self) -> Self { @@ -89,8 +89,8 @@ macro_rules! impl_clone_for { } } }; - (tuple $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:tt$(, $field2:tt)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { - impl$(<$($gen$(: $bound)?),+>)? Clone for $name$(<$($gen),+>)? + (tuple $name:ident$(<$($gen:ident$(: $bound1:tt$( + $bound2:tt)*)?),+$(,)?>)?, [$field1:tt$(, $field2:tt)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? Clone for $name$(<$($gen),+>)? $(where $($type: Clone,)+)? { fn clone(&self) -> Self { @@ -103,23 +103,30 @@ macro_rules! impl_clone_for { }; } +macro_rules! impl_zeroize_field_skip_pd { + ($self_:ident, $field:ident, PH) => {}; + ($self_:ident, $field:ident) => { + $self_.$field.zeroize(); + }; +} + macro_rules! impl_zeroize_on_drop_for { - (struct $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { - impl$(<$($gen$(: $bound)?),+>)? zeroize::Zeroize for $name$(<$($gen),+>)? + (struct $name:ident$(<$($gen:ident$(: $bound1:tt$( + $bound2:tt)*)?),+$(,)?>)?, [$(#[$pd1:ident] )?$field1:ident$(, $(#[$pd2:ident] )?$field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? zeroize::Zeroize for $name$(<$($gen),+>)? { fn zeroize(&mut self) { - self.$field1.zeroize(); - $(self.$field2.zeroize();)* + impl_zeroize_field_skip_pd!(self, $field1$(, $pd1)?); + $(impl_zeroize_field_skip_pd!(self, $field2$(, $pd2)?);)* } } - impl$(<$($gen$(: $bound)?),+>)? Drop for $name$(<$($gen),+>)? + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? Drop for $name$(<$($gen),+>)? { fn drop(&mut self) { #[allow(unused_imports)] use zeroize::Zeroize; - self.$field1.zeroize(); - $(self.$field2.zeroize();)* + impl_zeroize_field_skip_pd!(self, $field1$(, $pd1)?); + $(impl_zeroize_field_skip_pd!(self, $field2$(, $pd2)?);)* } } }; @@ -127,10 +134,10 @@ macro_rules! impl_zeroize_on_drop_for { /// Inner macro used for deriving `serde`'s `Serialize` and `Deserialize` traits. macro_rules! impl_serialize_and_deserialize_for { - ($t:ident) => { + ($name:ident$(<$($gen:ident$(: $bound1:tt$( + $bound2:tt)*)?),+$(,)?>)?) => { #[cfg(feature = "serialize")] #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] - impl serde::Serialize for $t { + impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? serde::Serialize for $name$(<$($gen),+>)? { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -145,28 +152,29 @@ macro_rules! impl_serialize_and_deserialize_for { #[cfg(feature = "serialize")] #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] - impl<'de, CS: CipherSuite> serde::Deserialize<'de> for $t { + impl<'de$(, $($gen$(: $bound1$(+ $bound2)*)?),+)?> serde::Deserialize<'de> for $name$(<$($gen),+>)? { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { if deserializer.is_human_readable() { let s = <&str>::deserialize(deserializer)?; - $t::::deserialize(&base64::decode(s).map_err(serde::de::Error::custom)?) + $name$(::<$($gen),+>)?::deserialize(&base64::decode(s).map_err(serde::de::Error::custom)?) .map_err(serde::de::Error::custom) } else { - struct ByteVisitor { - marker: core::marker::PhantomData, - } - impl<'de, CS: CipherSuite> serde::de::Visitor<'de> for ByteVisitor { - type Value = $t; + struct ByteVisitor$(<$($gen$(: $bound1$(+ $bound2)*)?),+> ( + #[allow(unused_parens)] + core::marker::PhantomData<($($gen),+)>, + ))?; + impl<'de$(, $($gen$(: $bound1$(+ $bound2)*)?),+)?> serde::de::Visitor<'de> for ByteVisitor$(<$($gen),+>)? { + type Value = $name$(<$($gen),+>)?; fn expecting( &self, formatter: &mut core::fmt::Formatter, ) -> core::fmt::Result { formatter.write_str(core::concat!( "the byte representation of a ", - core::stringify!($t) + core::stringify!($name) )) } @@ -174,20 +182,20 @@ macro_rules! impl_serialize_and_deserialize_for { where E: serde::de::Error, { - $t::::deserialize(value).map_err(|_| { + $name$(::<$($gen),+>)?::deserialize(value).map_err(|_| { serde::de::Error::invalid_value( serde::de::Unexpected::Bytes(value), &core::concat!( "invalid byte sequence for ", - core::stringify!($t) + core::stringify!($name) ), ) }) } } - deserializer.deserialize_bytes(ByteVisitor:: { - marker: core::marker::PhantomData, - }) + deserializer.deserialize_bytes(ByteVisitor$(::<$($gen),+> ( + core::marker::PhantomData, + ))?) } } } @@ -196,10 +204,10 @@ macro_rules! impl_serialize_and_deserialize_for { // Convenience macro for implementing all of the above traits macro_rules! impl_traits_for { - (struct $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { - impl_debug_eq_hash_for!(struct $name$(<$($gen$(: $bound)?),+>)?, [$field1$(, $field2)*], $([$($type),+])?); - impl_clone_for!(struct $name$(<$($gen$(: $bound)?),+>)?, [$field1$(, $field2)*], $([$($type),+])?); - impl_zeroize_on_drop_for!(struct $name$(<$($gen$(: $bound)?),+>)?, [$field1$(, $field2)*], $([$($type),+])?); - impl_serialize_and_deserialize_for!($name); + (struct $name:ident$(<$($gen:ident$(: $bound1:tt$( + $bound2:tt)*)?),+$(,)?>)?, [$(#[$pd1:ident] )?$field1:ident$(, $(#[$pd2:ident] )?$field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => { + impl_debug_eq_hash_for!(struct $name$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)?, [$field1$(, $field2)*], $([$($type),+])?); + impl_clone_for!(struct $name$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)?, [$field1$(, $field2)*], $([$($type),+])?); + impl_zeroize_on_drop_for!(struct $name$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)?, [$(#[$pd1] )?$field1$(, $(#[$pd2] )?$field2)*], $([$($type),+])?); + impl_serialize_and_deserialize_for!($name$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)?); } } diff --git a/src/lib.rs b/src/lib.rs index 9b4437c..449866d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,12 +24,8 @@ //! We will use the following choices in this example: //! //! ``` -//! use voprf::CipherSuite; -//! struct Default; -//! impl CipherSuite for Default { -//! type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! type Hash = sha2::Sha512; -//! } +//! type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! type Hash = sha2::Sha512; //! ``` //! //! ## Modes of Operation @@ -56,17 +52,13 @@ //! client evaluations. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! use voprf::NonVerifiableServer; //! use rand::{rngs::OsRng, RngCore}; //! //! let mut server_rng = OsRng; -//! let server = NonVerifiableServer::::new(&mut server_rng) +//! let server = NonVerifiableServer::::new(&mut server_rng) //! .expect("Unable to construct server"); //! ``` //! @@ -79,17 +71,13 @@ //! step of the VOPRF protocol. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! use voprf::NonVerifiableClient; //! use rand::{rngs::OsRng, RngCore}; //! //! let mut client_rng = OsRng; -//! let client_blind_result = NonVerifiableClient::::blind( +//! let client_blind_result = NonVerifiableClient::::blind( //! b"input", //! &mut client_rng, //! ).expect("Unable to construct client"); @@ -104,23 +92,19 @@ //! [EvaluationElement] to be sent to the client. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! # use voprf::NonVerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # //! # let mut client_rng = OsRng; -//! # let client_blind_result = NonVerifiableClient::::blind( +//! # let client_blind_result = NonVerifiableClient::::blind( //! # b"input", //! # &mut client_rng, //! # ).expect("Unable to construct client"); //! # use voprf::NonVerifiableServer; //! # let mut server_rng = OsRng; -//! # let server = NonVerifiableServer::::new(&mut server_rng) +//! # let server = NonVerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); //! use voprf::Metadata; //! let server_evaluate_result = server.evaluate( @@ -138,23 +122,19 @@ //! output for the protocol. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! # use voprf::NonVerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # //! # let mut client_rng = OsRng; -//! # let client_blind_result = NonVerifiableClient::::blind( +//! # let client_blind_result = NonVerifiableClient::::blind( //! # b"input", //! # &mut client_rng, //! # ).expect("Unable to construct client"); //! # use voprf::NonVerifiableServer; //! # let mut server_rng = OsRng; -//! # let server = NonVerifiableServer::::new(&mut server_rng) +//! # let server = NonVerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); //! # let server_evaluate_result = server.evaluate( //! # client_blind_result.message, @@ -166,7 +146,7 @@ //! &Metadata::none(), //! ).expect("Unable to perform client finalization"); //! -//! println!("VOPRF output: {:?}", client_finalize_result.output.to_vec()); +//! println!("VOPRF output: {:?}", client_finalize_result.to_vec()); //! ``` //! //! ## Verifiable Mode @@ -189,17 +169,13 @@ //! client evaluations. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! use voprf::VerifiableServer; //! use rand::{rngs::OsRng, RngCore}; //! //! let mut server_rng = OsRng; -//! let server = VerifiableServer::::new(&mut server_rng) +//! let server = VerifiableServer::::new(&mut server_rng) //! .expect("Unable to construct server"); //! //! // To be sent to the client @@ -219,17 +195,13 @@ //! step of the VOPRF protocol. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! use voprf::VerifiableClient; //! use rand::{rngs::OsRng, RngCore}; //! //! let mut client_rng = OsRng; -//! let client_blind_result = VerifiableClient::::blind( +//! let client_blind_result = VerifiableClient::::blind( //! b"input", //! &mut client_rng, //! ).expect("Unable to construct client"); @@ -244,23 +216,19 @@ //! [EvaluationElement] to be sent to the client along with a proof. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # //! # let mut client_rng = OsRng; -//! # let client_blind_result = VerifiableClient::::blind( +//! # let client_blind_result = VerifiableClient::::blind( //! # b"input", //! # &mut client_rng, //! # ).expect("Unable to construct client"); //! # use voprf::VerifiableServer; //! # let mut server_rng = OsRng; -//! # let server = VerifiableServer::::new(&mut server_rng) +//! # let server = VerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); //! use voprf::Metadata; //! let server_evaluate_result = server.evaluate( @@ -280,23 +248,19 @@ //! output for the protocol. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # //! # let mut client_rng = OsRng; -//! # let client_blind_result = VerifiableClient::::blind( +//! # let client_blind_result = VerifiableClient::::blind( //! # b"input", //! # &mut client_rng, //! # ).expect("Unable to construct client"); //! # use voprf::VerifiableServer; //! # let mut server_rng = OsRng; -//! # let server = VerifiableServer::::new(&mut server_rng) +//! # let server = VerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); //! # let server_evaluate_result = server.evaluate( //! # &mut server_rng, @@ -311,7 +275,7 @@ //! &Metadata::none(), //! ).expect("Unable to perform client finalization"); //! -//! println!("VOPRF output: {:?}", client_finalize_result.output.to_vec()); +//! println!("VOPRF output: {:?}", client_finalize_result.to_vec()); //! ``` //! //! # Advanced Usage @@ -333,12 +297,8 @@ //! states and messages: //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -346,7 +306,7 @@ //! let mut client_states = vec![]; //! let mut client_messages = vec![]; //! for _ in 0..10 { -//! let client_blind_result = VerifiableClient::::blind( +//! let client_blind_result = VerifiableClient::::blind( //! b"input", //! &mut client_rng, //! ).expect("Unable to construct client"); @@ -361,12 +321,8 @@ //! along with a single proof: //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -374,7 +330,7 @@ //! # let mut client_states = vec![]; //! # let mut client_messages = vec![]; //! # for _ in 0..10 { -//! # let client_blind_result = VerifiableClient::::blind( +//! # let client_blind_result = VerifiableClient::::blind( //! # b"input", //! # &mut client_rng, //! # ).expect("Unable to construct client"); @@ -384,7 +340,7 @@ //! # use voprf::Metadata; //! # use voprf::VerifiableServer; //! let mut server_rng = OsRng; -//! # let server = VerifiableServer::::new(&mut server_rng) +//! # let server = VerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); //! let server_batch_evaluate_result = server.batch_evaluate( //! &mut server_rng, @@ -400,12 +356,8 @@ //! verifies correctly. //! //! ``` -//! # use voprf::CipherSuite; -//! # struct Default; -//! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; -//! # type Hash = sha2::Sha512; -//! # } +//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type Hash = sha2::Sha512; //! # use voprf::VerifiableClient; //! # use rand::{rngs::OsRng, RngCore}; //! # @@ -413,7 +365,7 @@ //! # let mut client_states = vec![]; //! # let mut client_messages = vec![]; //! # for _ in 0..10 { -//! # let client_blind_result = VerifiableClient::::blind( +//! # let client_blind_result = VerifiableClient::::blind( //! # b"input", //! # &mut client_rng, //! # ).expect("Unable to construct client"); @@ -424,7 +376,7 @@ //! # use voprf::VerifiableServer; //! use voprf::BatchFinalizeInput; //! let mut server_rng = OsRng; -//! # let server = VerifiableServer::::new(&mut server_rng) +//! # let server = VerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); //! # let server_batch_evaluate_result = server.batch_evaluate( //! # &mut server_rng, @@ -442,7 +394,7 @@ //! &Metadata::none(), //! ).expect("Unable to perform client batch finalization"); //! -//! println!("VOPRF batch outputs: {:?}", client_batch_finalize_result.outputs); +//! println!("VOPRF batch outputs: {:?}", client_batch_finalize_result); //! ``` //! //! ## Metadata @@ -459,7 +411,7 @@ //! //! # Features //! -//! - The `p256` feature enables using p256 as the underlying group for the [CipherSuite] choice. +//! - 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 @@ -484,10 +436,8 @@ extern crate alloc; mod impls; #[macro_use] mod serialization; -mod ciphersuite; pub mod errors; pub mod group; -pub mod hash; mod voprf; #[cfg(test)] @@ -497,10 +447,9 @@ mod tests; pub use rand; -pub use crate::ciphersuite::CipherSuite; pub use crate::voprf::{ BatchFinalizeInput, BlindedElement, EvaluationElement, Metadata, NonVerifiableClient, - NonVerifiableClientBlindResult, NonVerifiableClientFinalizeResult, NonVerifiableServer, - NonVerifiableServerEvaluateResult, VerifiableClient, VerifiableClientBlindResult, - VerifiableClientFinalizeResult, VerifiableServer, VerifiableServerEvaluateResult, + NonVerifiableClientBlindResult, NonVerifiableServer, NonVerifiableServerEvaluateResult, + VerifiableClient, VerifiableClientBlindResult, VerifiableServer, + VerifiableServerEvaluateResult, }; diff --git a/src/serialization.rs b/src/serialization.rs index b90bd26..dd4b859 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -9,7 +9,6 @@ //! in the VOPRF protocol use crate::{ - ciphersuite::CipherSuite, errors::InternalError, group::Group, voprf::{ @@ -18,6 +17,8 @@ use crate::{ }, }; use alloc::vec::Vec; +use core::marker::PhantomData; +use digest::{BlockInput, Digest}; use generic_array::{typenum::Unsigned, GenericArray}; ////////////////////////////////////////////////////////// @@ -25,35 +26,35 @@ use generic_array::{typenum::Unsigned, GenericArray}; // ==================================================== // ////////////////////////////////////////////////////////// -impl NonVerifiableClient { +impl NonVerifiableClient { /// Serialization into bytes pub fn serialize(&self) -> Vec { - [ - CS::Group::scalar_as_bytes(self.blind).to_vec(), - self.data.clone(), - ] - .concat() + [G::scalar_as_bytes(self.blind).to_vec(), self.data.clone()].concat() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let scalar_len = ::ScalarLen::USIZE; + let scalar_len = ::ScalarLen::USIZE; if input.len() < scalar_len { return Err(InternalError::SizeError); } - let blind = CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?; + let blind = G::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?; let data = input[scalar_len..].to_vec(); - Ok(Self { blind, data }) + Ok(Self { + blind, + data, + hash: PhantomData, + }) } } -impl VerifiableClient { +impl VerifiableClient { /// Serialization into bytes pub fn serialize(&self) -> Vec { [ - CS::Group::scalar_as_bytes(self.blind).to_vec(), + G::scalar_as_bytes(self.blind).to_vec(), self.blinded_element.to_arr().to_vec(), self.data.clone(), ] @@ -62,14 +63,14 @@ impl VerifiableClient { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let scalar_len = ::ScalarLen::USIZE; - let elem_len = ::ElemLen::USIZE; + let scalar_len = ::ScalarLen::USIZE; + let elem_len = ::ElemLen::USIZE; if input.len() < scalar_len + elem_len { return Err(InternalError::SizeError); } - let blind = CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?; - let blinded_element = CS::Group::from_element_slice(GenericArray::from_slice( + let blind = G::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?; + let blinded_element = G::from_element_slice(GenericArray::from_slice( &input[scalar_len..scalar_len + elem_len], ))?; let data = input[scalar_len + elem_len..].to_vec(); @@ -78,34 +79,38 @@ impl VerifiableClient { blind, blinded_element, data, + hash: PhantomData, }) } } -impl NonVerifiableServer { +impl NonVerifiableServer { /// Serialization into bytes pub fn serialize(&self) -> Vec { - CS::Group::scalar_as_bytes(self.sk).to_vec() + G::scalar_as_bytes(self.sk).to_vec() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let scalar_len = ::ScalarLen::USIZE; + let scalar_len = ::ScalarLen::USIZE; if input.len() != scalar_len { return Err(InternalError::SizeError); } - let sk = CS::Group::from_scalar_slice(GenericArray::from_slice(input))?; + let sk = G::from_scalar_slice(GenericArray::from_slice(input))?; - Ok(Self { sk }) + Ok(Self { + sk, + hash: PhantomData, + }) } } -impl VerifiableServer { +impl VerifiableServer { /// Serialization into bytes pub fn serialize(&self) -> Vec { [ - CS::Group::scalar_as_bytes(self.sk).to_vec(), + G::scalar_as_bytes(self.sk).to_vec(), self.pk.to_arr().to_vec(), ] .concat() @@ -113,43 +118,48 @@ impl VerifiableServer { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let scalar_len = ::ScalarLen::USIZE; - let elem_len = ::ElemLen::USIZE; + let scalar_len = ::ScalarLen::USIZE; + let elem_len = ::ElemLen::USIZE; if input.len() != scalar_len + elem_len { return Err(InternalError::SizeError); } - let sk = CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?; - let pk = CS::Group::from_element_slice(GenericArray::from_slice(&input[scalar_len..]))?; + let sk = G::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?; + let pk = G::from_element_slice(GenericArray::from_slice(&input[scalar_len..]))?; - Ok(Self { sk, pk }) + Ok(Self { + sk, + pk, + hash: PhantomData, + }) } } -impl Proof { +impl Proof { /// Serialization into bytes pub fn serialize(&self) -> Vec { [ - CS::Group::scalar_as_bytes(self.c_scalar), - CS::Group::scalar_as_bytes(self.s_scalar), + G::scalar_as_bytes(self.c_scalar), + G::scalar_as_bytes(self.s_scalar), ] .concat() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let scalar_len = ::ScalarLen::USIZE; + let scalar_len = ::ScalarLen::USIZE; if input.len() < scalar_len + scalar_len { return Err(InternalError::SizeError); } Ok(Proof { - c_scalar: CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?, - s_scalar: CS::Group::from_scalar_slice(GenericArray::from_slice(&input[scalar_len..]))?, + c_scalar: G::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?, + s_scalar: G::from_scalar_slice(GenericArray::from_slice(&input[scalar_len..]))?, + hash: PhantomData, }) } } -impl BlindedElement { +impl BlindedElement { /// Serialization into bytes pub fn serialize(&self) -> Vec { self.value.to_arr().to_vec() @@ -158,12 +168,13 @@ impl BlindedElement { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { Ok(Self { - value: CS::Group::from_element_slice(GenericArray::from_slice(input))?, + value: G::from_element_slice(GenericArray::from_slice(input))?, + hash: PhantomData, }) } } -impl EvaluationElement { +impl EvaluationElement { /// Serialization into bytes pub fn serialize(&self) -> Vec { self.value.to_arr().to_vec() @@ -172,7 +183,8 @@ impl EvaluationElement { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { Ok(Self { - value: CS::Group::from_element_slice(GenericArray::from_slice(input))?, + value: G::from_element_slice(GenericArray::from_slice(input))?, + hash: PhantomData, }) } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 2f6d2e0..7665c25 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -9,18 +9,3 @@ mod mock_rng; mod parser; mod voprf_test_vectors; mod voprf_vectors; - -/// Ciphersuite definitions for tests -pub(crate) struct Ristretto255Sha512; -impl crate::CipherSuite for Ristretto255Sha512 { - type Group = curve25519_dalek::ristretto::RistrettoPoint; - type Hash = sha2::Sha512; -} - -#[cfg(feature = "p256")] -pub(crate) struct P256Sha256; -#[cfg(feature = "p256")] -impl crate::CipherSuite for P256Sha256 { - type Group = p256_::ProjectivePoint; - type Hash = sha2::Sha256; -} diff --git a/src/tests/voprf_test_vectors.rs b/src/tests/voprf_test_vectors.rs index 87b2684..ffbb8d1 100644 --- a/src/tests/voprf_test_vectors.rs +++ b/src/tests/voprf_test_vectors.rs @@ -6,7 +6,6 @@ // of this source tree. use crate::{ - ciphersuite::CipherSuite, errors::InternalError, group::Group, tests::{mock_rng::CycleRng, parser::*}, @@ -17,6 +16,7 @@ use crate::{ }; use alloc::string::ToString; use alloc::vec::Vec; +use digest::{BlockInput, Digest}; use generic_array::GenericArray; use json::JsonValue; @@ -85,7 +85,8 @@ fn test_vectors() -> Result<(), InternalError> { let rfc = json::parse(rfc_to_json(super::voprf_vectors::VECTORS).as_str()) .expect("Could not parse json"); - use crate::tests::Ristretto255Sha512; + use curve25519_dalek::ristretto::RistrettoPoint; + use sha2::Sha512; let ristretto_base_tvs = json_to_test_vectors!( rfc, @@ -99,19 +100,20 @@ fn test_vectors() -> Result<(), InternalError> { String::from("Verifiable") ); - test_base_seed_to_key::(&ristretto_base_tvs)?; - test_base_blind::(&ristretto_base_tvs)?; - test_base_evaluate::(&ristretto_base_tvs)?; - test_base_finalize::(&ristretto_base_tvs)?; + test_base_seed_to_key::(&ristretto_base_tvs)?; + test_base_blind::(&ristretto_base_tvs)?; + test_base_evaluate::(&ristretto_base_tvs)?; + test_base_finalize::(&ristretto_base_tvs)?; - test_verifiable_seed_to_key::(&ristretto_verifiable_tvs)?; - test_verifiable_blind::(&ristretto_verifiable_tvs)?; - test_verifiable_evaluate::(&ristretto_verifiable_tvs)?; - test_verifiable_finalize::(&ristretto_verifiable_tvs)?; + test_verifiable_seed_to_key::(&ristretto_verifiable_tvs)?; + test_verifiable_blind::(&ristretto_verifiable_tvs)?; + test_verifiable_evaluate::(&ristretto_verifiable_tvs)?; + test_verifiable_finalize::(&ristretto_verifiable_tvs)?; #[cfg(feature = "p256")] { - use crate::tests::P256Sha256; + use p256_::ProjectivePoint; + use sha2::Sha256; let p256_base_tvs = json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("Base")); @@ -122,43 +124,43 @@ fn test_vectors() -> Result<(), InternalError> { String::from("Verifiable") ); - test_base_seed_to_key::(&p256_base_tvs)?; - test_base_blind::(&p256_base_tvs)?; - test_base_evaluate::(&p256_base_tvs)?; - test_base_finalize::(&p256_base_tvs)?; + test_base_seed_to_key::(&p256_base_tvs)?; + test_base_blind::(&p256_base_tvs)?; + test_base_evaluate::(&p256_base_tvs)?; + test_base_finalize::(&p256_base_tvs)?; - test_verifiable_seed_to_key::(&p256_verifiable_tvs)?; - test_verifiable_blind::(&p256_verifiable_tvs)?; - test_verifiable_evaluate::(&p256_verifiable_tvs)?; - test_verifiable_finalize::(&p256_verifiable_tvs)?; + test_verifiable_seed_to_key::(&p256_verifiable_tvs)?; + test_verifiable_blind::(&p256_verifiable_tvs)?; + test_verifiable_evaluate::(&p256_verifiable_tvs)?; + test_verifiable_finalize::(&p256_verifiable_tvs)?; } Ok(()) } -fn test_base_seed_to_key( +fn test_base_seed_to_key( tvs: &[VOPRFTestVectorParameters], ) -> Result<(), InternalError> { for parameters in tvs { - let server = NonVerifiableServer::::new_from_seed(¶meters.seed)?; + let server = NonVerifiableServer::::new_from_seed(¶meters.seed)?; assert_eq!( ¶meters.sksm, - &CS::Group::scalar_as_bytes(server.get_private_key()).to_vec() + &G::scalar_as_bytes(server.get_private_key()).to_vec() ); } Ok(()) } -fn test_verifiable_seed_to_key( +fn test_verifiable_seed_to_key( tvs: &[VOPRFTestVectorParameters], ) -> Result<(), InternalError> { for parameters in tvs { - let server = VerifiableServer::::new_from_seed(¶meters.seed)?; + let server = VerifiableServer::::new_from_seed(¶meters.seed)?; assert_eq!( ¶meters.sksm, - &CS::Group::scalar_as_bytes(server.get_private_key()).to_vec() + &G::scalar_as_bytes(server.get_private_key()).to_vec() ); assert_eq!(¶meters.pksm, &server.get_public_key().to_arr().to_vec()); } @@ -166,17 +168,17 @@ fn test_verifiable_seed_to_key( } // Tests input -> blind, blinded_element -fn test_base_blind( +fn test_base_blind( tvs: &[VOPRFTestVectorParameters], ) -> Result<(), InternalError> { for parameters in tvs { for i in 0..parameters.input.len() { let mut rng = CycleRng::new(parameters.blind[i].to_vec()); - let client_result = NonVerifiableClient::::blind(¶meters.input[i], &mut rng)?; + let client_result = NonVerifiableClient::::blind(¶meters.input[i], &mut rng)?; assert_eq!( ¶meters.blind[i], - &CS::Group::scalar_as_bytes(client_result.state.get_blind()).to_vec() + &G::scalar_as_bytes(client_result.state.get_blind()).to_vec() ); assert_eq!( ¶meters.blinded_element[i], @@ -188,18 +190,18 @@ fn test_base_blind( } // Tests input -> blind, blinded_element -fn test_verifiable_blind( +fn test_verifiable_blind( tvs: &[VOPRFTestVectorParameters], ) -> Result<(), InternalError> { for parameters in tvs { for i in 0..parameters.input.len() { let mut rng = CycleRng::new(parameters.blind[i].to_vec()); let client_blind_result = - VerifiableClient::::blind(¶meters.input[i], &mut rng)?; + VerifiableClient::::blind(¶meters.input[i], &mut rng)?; assert_eq!( ¶meters.blind[i], - &CS::Group::scalar_as_bytes(client_blind_result.state.get_blind()).to_vec() + &G::scalar_as_bytes(client_blind_result.state.get_blind()).to_vec() ); assert_eq!( ¶meters.blinded_element[i], @@ -211,12 +213,12 @@ fn test_verifiable_blind( } // Tests sksm, blinded_element -> evaluation_element -fn test_base_evaluate( +fn test_base_evaluate( tvs: &[VOPRFTestVectorParameters], ) -> Result<(), InternalError> { for parameters in tvs { for i in 0..parameters.input.len() { - let server = NonVerifiableServer::::new_with_key(¶meters.sksm)?; + let server = NonVerifiableServer::::new_with_key(¶meters.sksm)?; let server_result = server.evaluate( BlindedElement::deserialize(¶meters.blinded_element[i])?, &Metadata(parameters.info.clone()), @@ -231,12 +233,12 @@ fn test_base_evaluate( Ok(()) } -fn test_verifiable_evaluate( +fn test_verifiable_evaluate( tvs: &[VOPRFTestVectorParameters], ) -> Result<(), InternalError> { for parameters in tvs { let mut rng = CycleRng::new(parameters.proof_random_scalar.clone()); - let server = VerifiableServer::::new_with_key(¶meters.sksm)?; + let server = VerifiableServer::::new_with_key(¶meters.sksm)?; let mut blinded_elements = vec![]; for blinded_element_bytes in ¶meters.blinded_element { @@ -262,14 +264,14 @@ fn test_verifiable_evaluate( } // Tests input, blind, evaluation_element -> output -fn test_base_finalize( +fn test_base_finalize( tvs: &[VOPRFTestVectorParameters], ) -> Result<(), InternalError> { for parameters in tvs { for i in 0..parameters.input.len() { - let client = NonVerifiableClient::::from_data_and_blind( + let client = NonVerifiableClient::::from_data_and_blind( ¶meters.input[i], - ::from_scalar_slice(&GenericArray::clone_from_slice( + ::from_scalar_slice(&GenericArray::clone_from_slice( ¶meters.blind[i], ))?, ); @@ -279,27 +281,24 @@ fn test_base_finalize( &Metadata(parameters.info.clone()), )?; - assert_eq!( - ¶meters.output[i], - &client_finalize_result.output.to_vec() - ); + assert_eq!(¶meters.output[i], &client_finalize_result.to_vec()); } } Ok(()) } -fn test_verifiable_finalize( +fn test_verifiable_finalize( tvs: &[VOPRFTestVectorParameters], ) -> Result<(), InternalError> { for parameters in tvs { let mut clients = vec![]; for i in 0..parameters.input.len() { - let client = VerifiableClient::::from_data_and_blind( + let client = VerifiableClient::::from_data_and_blind( ¶meters.input[i], - ::from_scalar_slice(&GenericArray::clone_from_slice( + ::from_scalar_slice(&GenericArray::clone_from_slice( ¶meters.blind[i], ))?, - ::from_element_slice(&GenericArray::clone_from_slice( + ::from_element_slice(&GenericArray::clone_from_slice( ¶meters.blinded_element[i], ))?, ); @@ -318,14 +317,13 @@ fn test_verifiable_finalize( let batch_result = VerifiableClient::batch_finalize( batch_finalize_input, Proof::deserialize(¶meters.proof)?, - CS::Group::from_element_slice(GenericArray::from_slice(¶meters.pksm))?, + G::from_element_slice(GenericArray::from_slice(¶meters.pksm))?, &Metadata(parameters.info.clone()), )?; assert_eq!( parameters.output, batch_result - .outputs .iter() .map(|arr| arr.to_vec()) .collect::>>() diff --git a/src/voprf.rs b/src/voprf.rs index 793fa62..42bd562 100644 --- a/src/voprf.rs +++ b/src/voprf.rs @@ -8,14 +8,14 @@ //! Contains the main VOPRF API use crate::{ - ciphersuite::CipherSuite, errors::InternalError, group::Group, serialization::{i2osp, serialize}, }; use alloc::vec; use alloc::vec::Vec; -use digest::Digest; +use core::marker::PhantomData; +use digest::{BlockInput, Digest}; use generic_array::{typenum::Unsigned, GenericArray}; use rand::{CryptoRng, RngCore}; @@ -49,88 +49,95 @@ enum Mode { /// A client which engages with a [NonVerifiableServer] /// in base mode, meaning that the OPRF outputs are not /// verifiable. -pub struct NonVerifiableClient { - pub(crate) blind: ::Scalar, +pub struct NonVerifiableClient { + pub(crate) blind: ::Scalar, pub(crate) data: Vec, + pub(crate) hash: PhantomData, } impl_traits_for!( - struct NonVerifiableClient, - [blind, data], - [::Scalar], + struct NonVerifiableClient, + [blind, data, #[PH] hash], + [::Scalar], ); /// A client which engages with a [VerifiableServer] /// in verifiable mode, meaning that the OPRF outputs /// can be checked against a server public key. -pub struct VerifiableClient { - pub(crate) blind: ::Scalar, - pub(crate) blinded_element: CS::Group, +pub struct VerifiableClient { + pub(crate) blind: ::Scalar, + pub(crate) blinded_element: G, pub(crate) data: alloc::vec::Vec, + pub(crate) hash: PhantomData, } impl_traits_for!( - struct VerifiableClient, - [blind, blinded_element, data], - [::Scalar, CS::Group], + struct VerifiableClient, + [blind, blinded_element, data, #[PH] hash], + [::Scalar, G], ); /// A server which engages with a [NonVerifiableClient] /// in base mode, meaning that the OPRF outputs are not /// verifiable. -pub struct NonVerifiableServer { - pub(crate) sk: ::Scalar, +pub struct NonVerifiableServer { + pub(crate) sk: ::Scalar, + pub(crate) hash: PhantomData, } impl_traits_for!( - struct NonVerifiableServer, - [sk], - [::Scalar], + struct NonVerifiableServer, + [sk, #[PH] hash], + [::Scalar], ); /// A server which engages with a [VerifiableClient] /// in verifiable mode, meaning that the OPRF outputs /// can be checked against a server public key. -pub struct VerifiableServer { - pub(crate) sk: ::Scalar, - pub(crate) pk: CS::Group, +pub struct VerifiableServer { + pub(crate) sk: ::Scalar, + pub(crate) pk: G, + pub(crate) hash: PhantomData, } impl_traits_for!( - struct VerifiableServer, - [sk, pk], - [::Scalar, CS::Group], + struct VerifiableServer, + [sk, pk, #[PH] hash], + [::Scalar, G], ); /// A proof produced by a [VerifiableServer] that /// the OPRF output matches against a server public key. -pub struct Proof { - pub(crate) c_scalar: ::Scalar, - pub(crate) s_scalar: ::Scalar, +pub struct Proof { + pub(crate) c_scalar: ::Scalar, + pub(crate) s_scalar: ::Scalar, + pub(crate) hash: PhantomData, } impl_traits_for!( - struct Proof, - [c_scalar, s_scalar], - [::Scalar], + struct Proof, + [c_scalar, s_scalar, #[PH] hash], + [::Scalar], ); /// The first client message sent from a client (either verifiable or not) /// to a server (either verifiable or not). -pub struct BlindedElement { - pub(crate) value: CS::Group, +pub struct BlindedElement { + pub(crate) value: G, + pub(crate) hash: PhantomData, } impl_traits_for!( - struct BlindedElement, - [value], - [CS::Group], + struct BlindedElement, + [value, #[PH] hash], + [G], ); /// The server's response to the [BlindedElement] message from /// a client (either verifiable or not) /// to a server (either verifiable or not). -pub struct EvaluationElement { - pub(crate) value: CS::Group, +pub struct EvaluationElement { + pub(crate) value: G, + pub(crate) hash: PhantomData, } impl_traits_for!( - struct EvaluationElement, - [value], - [CS::Group], + struct EvaluationElement, + [value, #[PH] hash], + [G], ); ///////////////////////// @@ -138,20 +145,22 @@ impl_traits_for!( // =================== // ///////////////////////// -impl NonVerifiableClient { +impl NonVerifiableClient { /// Computes the first step for the multiplicative blinding version of DH-OPRF. pub fn blind( input: &[u8], blinding_factor_rng: &mut R, - ) -> Result, InternalError> { - let (blind, blinded_element) = blind::(input, blinding_factor_rng, Mode::Base)?; + ) -> Result, InternalError> { + let (blind, blinded_element) = blind::(input, blinding_factor_rng, Mode::Base)?; Ok(NonVerifiableClientBlindResult { state: Self { data: input.to_vec(), blind, + hash: PhantomData, }, message: BlindedElement { value: blinded_element, + hash: PhantomData, }, }) } @@ -160,53 +169,54 @@ impl NonVerifiableClient { /// the client unblinds the server's message. pub fn finalize( &self, - evaluation_element: EvaluationElement, + evaluation_element: EvaluationElement, metadata: &Metadata, - ) -> Result, InternalError> { + ) -> Result::OutputSize>, InternalError> { let unblinded_element = - evaluation_element.value * &::scalar_invert(&self.blind); - let outputs = finalize_after_unblind::( + evaluation_element.value * &::scalar_invert(&self.blind); + let outputs = finalize_after_unblind::( &[(self.data.clone(), unblinded_element)], &metadata.0, Mode::Base, )?; - Ok(NonVerifiableClientFinalizeResult { - output: outputs[0].clone(), - }) + Ok(outputs[0].clone()) } #[cfg(test)] /// Only used for test functions - pub fn from_data_and_blind(data: &[u8], blind: ::Scalar) -> Self { + pub fn from_data_and_blind(data: &[u8], blind: ::Scalar) -> Self { Self { data: data.to_vec(), blind, + hash: PhantomData, } } #[cfg(test)] /// Only used for test functions - pub fn get_blind(&self) -> ::Scalar { + pub fn get_blind(&self) -> ::Scalar { self.blind } } -impl VerifiableClient { +impl VerifiableClient { /// Computes the first step for the multiplicative blinding version of DH-OPRF. pub fn blind( input: &[u8], blinding_factor_rng: &mut R, - ) -> Result, InternalError> { + ) -> Result, InternalError> { let (blind, blinded_element) = - blind::(input, blinding_factor_rng, Mode::Verifiable)?; + blind::(input, blinding_factor_rng, Mode::Verifiable)?; Ok(VerifiableClientBlindResult { state: Self { data: input.to_vec(), blind, blinded_element, + hash: PhantomData, }, message: BlindedElement { value: blinded_element, + hash: PhantomData, }, }) } @@ -215,28 +225,26 @@ impl VerifiableClient { /// the client unblinds the server's message. pub fn finalize( &self, - evaluation_element: EvaluationElement, - proof: Proof, - pk: CS::Group, + evaluation_element: EvaluationElement, + proof: Proof, + pk: G, metadata: &Metadata, - ) -> Result, InternalError> { + ) -> Result::OutputSize>, InternalError> { let batch_finalize_input = BatchFinalizeInput::new(vec![self.clone()], vec![evaluation_element]); let batch_result = Self::batch_finalize(batch_finalize_input, proof, pk, metadata)?; - Ok(VerifiableClientFinalizeResult { - output: batch_result.outputs[0].clone(), - }) + Ok(batch_result[0].clone()) } /// Allows for batching of the finalization of multiple [VerifiableClient] and [EvaluationElement] pairs #[allow(clippy::type_complexity)] pub fn batch_finalize( - batch_finalize_input: BatchFinalizeInput, - proof: Proof, - pk: CS::Group, + batch_finalize_input: BatchFinalizeInput, + proof: Proof, + pk: G, metadata: &Metadata, - ) -> Result, InternalError> { - let batch_items: Vec> = batch_finalize_input + ) -> Result::OutputSize>>, InternalError> { + let batch_items: Vec> = batch_finalize_input .clients .iter() .zip(batch_finalize_input.messages.iter()) @@ -245,53 +253,53 @@ impl VerifiableClient { evaluation_element: evaluation_element.clone(), blinded_element: BlindedElement { value: client.blinded_element, + hash: PhantomData, }, }) .collect(); let unblinded_elements = verifiable_unblind(&batch_items, pk, proof, &metadata.0)?; - let inputs_and_unblinded_elements: Vec<(Vec, CS::Group)> = batch_finalize_input + let inputs_and_unblinded_elements: Vec<(Vec, G)> = batch_finalize_input .clients .iter() .zip(unblinded_elements.iter()) .map(|(client, &unblinded_element)| (client.data.clone(), unblinded_element)) .collect(); - Ok(VerifiableClientBatchFinalizeResult { - outputs: finalize_after_unblind::( - &inputs_and_unblinded_elements, - &metadata.0, - Mode::Verifiable, - )?, - }) + finalize_after_unblind::( + &inputs_and_unblinded_elements, + &metadata.0, + Mode::Verifiable, + ) } #[cfg(test)] /// Only used for test functions pub fn from_data_and_blind( data: &[u8], - blind: ::Scalar, - blinded_element: CS::Group, + blind: ::Scalar, + blinded_element: G, ) -> Self { Self { data: data.to_vec(), blind, blinded_element, + hash: PhantomData, } } #[cfg(test)] /// Only used for test functions - pub fn get_blind(&self) -> ::Scalar { + pub fn get_blind(&self) -> ::Scalar { self.blind } } -impl NonVerifiableServer { +impl NonVerifiableServer { /// Produces a new instance of a [NonVerifiableServer] using a supplied RNG pub fn new(rng: &mut R) -> Result { - let mut seed = vec![0u8; ::OutputSize::USIZE]; + let mut seed = vec![0u8; ::OutputSize::USIZE]; rng.fill_bytes(&mut seed); Self::new_from_seed(&seed) } @@ -299,8 +307,11 @@ impl NonVerifiableServer { /// Produces a new instance of a [NonVerifiableServer] using a supplied set of bytes to /// represent the server's private key pub fn new_with_key(private_key_bytes: &[u8]) -> Result { - let sk = CS::Group::from_scalar_slice(&GenericArray::clone_from_slice(private_key_bytes))?; - Ok(Self { sk }) + let sk = G::from_scalar_slice(&GenericArray::clone_from_slice(private_key_bytes))?; + Ok(Self { + sk, + hash: PhantomData, + }) } /// Produces a new instance of a [NonVerifiableServer] using a supplied set of bytes which @@ -308,14 +319,17 @@ impl NonVerifiableServer { /// /// Corresponds to DeriveKeyPair() function from the VOPRF specification. pub fn new_from_seed(seed: &[u8]) -> Result { - let dst = [STR_HASH_TO_SCALAR, &get_context_string::(Mode::Base)?].concat(); - let sk = CS::Group::hash_to_scalar::(seed, &dst)?; - Ok(Self { sk }) + let dst = [STR_HASH_TO_SCALAR, &get_context_string::(Mode::Base)?].concat(); + let sk = G::hash_to_scalar::(seed, &dst)?; + Ok(Self { + sk, + hash: PhantomData, + }) } // Only used for tests #[cfg(test)] - pub fn get_private_key(&self) -> ::Scalar { + pub fn get_private_key(&self) -> ::Scalar { self.sk } @@ -323,31 +337,32 @@ impl NonVerifiableServer { /// message is sent from the server (who holds the OPRF key) to the client. pub fn evaluate( &self, - blinded_element: BlindedElement, + blinded_element: BlindedElement, metadata: &Metadata, - ) -> Result, InternalError> { + ) -> Result, InternalError> { let context = [ STR_CONTEXT, - &get_context_string::(Mode::Base)?, + &get_context_string::(Mode::Base)?, &serialize(&metadata.0, 2)?, ] .concat(); - let dst = [STR_HASH_TO_SCALAR, &get_context_string::(Mode::Base)?].concat(); - let m = CS::Group::hash_to_scalar::(&context, &dst)?; + let dst = [STR_HASH_TO_SCALAR, &get_context_string::(Mode::Base)?].concat(); + let m = G::hash_to_scalar::(&context, &dst)?; let t = self.sk + &m; - let evaluation_element = blinded_element.value * &CS::Group::scalar_invert(&t); + let evaluation_element = blinded_element.value * &G::scalar_invert(&t); Ok(NonVerifiableServerEvaluateResult { message: EvaluationElement { value: evaluation_element, + hash: PhantomData, }, }) } } -impl VerifiableServer { +impl VerifiableServer { /// Produces a new instance of a [VerifiableServer] using a supplied RNG pub fn new(rng: &mut R) -> Result { - let mut seed = vec![0u8; ::OutputSize::USIZE]; + let mut seed = vec![0u8; ::OutputSize::USIZE]; rng.fill_bytes(&mut seed); Self::new_from_seed(&seed) } @@ -355,9 +370,13 @@ impl VerifiableServer { /// Produces a new instance of a [VerifiableServer] using a supplied set of bytes to /// represent the server's private key pub fn new_with_key(key: &[u8]) -> Result { - let sk = CS::Group::from_scalar_slice(&GenericArray::clone_from_slice(key))?; - let pk = CS::Group::base_point() * &sk; - Ok(Self { sk, pk }) + let sk = G::from_scalar_slice(&GenericArray::clone_from_slice(key))?; + let pk = G::base_point() * &sk; + Ok(Self { + sk, + pk, + hash: PhantomData, + }) } /// Produces a new instance of a [VerifiableServer] using a supplied set of bytes which @@ -367,17 +386,21 @@ impl VerifiableServer { pub fn new_from_seed(seed: &[u8]) -> Result { let dst = [ STR_HASH_TO_SCALAR, - &get_context_string::(Mode::Verifiable)?, + &get_context_string::(Mode::Verifiable)?, ] .concat(); - let sk = CS::Group::hash_to_scalar::(seed, &dst)?; - let pk = CS::Group::base_point() * &sk; - Ok(Self { sk, pk }) + let sk = G::hash_to_scalar::(seed, &dst)?; + let pk = G::base_point() * &sk; + Ok(Self { + sk, + pk, + hash: PhantomData, + }) } // Only used for tests #[cfg(test)] - pub fn get_private_key(&self) -> ::Scalar { + pub fn get_private_key(&self) -> ::Scalar { self.sk } @@ -386,9 +409,9 @@ impl VerifiableServer { pub fn evaluate( &self, rng: &mut R, - blinded_element: BlindedElement, + blinded_element: BlindedElement, metadata: &Metadata, - ) -> Result, InternalError> { + ) -> Result, InternalError> { let batch_result = self.batch_evaluate(rng, &[blinded_element], metadata)?; Ok(VerifiableServerEvaluateResult { message: batch_result.messages[0].clone(), @@ -400,30 +423,31 @@ impl VerifiableServer { pub fn batch_evaluate( &self, rng: &mut R, - blinded_elements: &[BlindedElement], + blinded_elements: &[BlindedElement], metadata: &Metadata, - ) -> Result, InternalError> { + ) -> Result, InternalError> { let context = [ STR_CONTEXT, - &get_context_string::(Mode::Verifiable)?, + &get_context_string::(Mode::Verifiable)?, &serialize(&metadata.0, 2)?, ] .concat(); let dst = [ STR_HASH_TO_SCALAR, - &get_context_string::(Mode::Verifiable)?, + &get_context_string::(Mode::Verifiable)?, ] .concat(); - let m = CS::Group::hash_to_scalar::(&context, &dst)?; + let m = G::hash_to_scalar::(&context, &dst)?; let t = self.sk + &m; - let evaluation_elements: Vec> = blinded_elements + let evaluation_elements: Vec> = blinded_elements .iter() .map(|x| EvaluationElement { - value: x.value * &CS::Group::scalar_invert(&t), + value: x.value * &G::scalar_invert(&t), + hash: PhantomData, }) .collect(); - let g = CS::Group::base_point(); + let g = G::base_point(); let u = g * &t; let proof = generate_proof(rng, t, g, u, &evaluation_elements, blinded_elements)?; @@ -435,7 +459,7 @@ impl VerifiableServer { } /// Retrieves the server's public key - pub fn get_public_key(&self) -> CS::Group { + pub fn get_public_key(&self) -> G { self.pk } } @@ -463,71 +487,56 @@ impl Metadata { ///////////////////////// /// Contains the fields that are returned by a non-verifiable client blind -pub struct NonVerifiableClientBlindResult { +pub struct NonVerifiableClientBlindResult { /// The state to be persisted on the client - pub state: NonVerifiableClient, + pub state: NonVerifiableClient, /// The message to send to the server - pub message: BlindedElement, + pub message: BlindedElement, } /// Contains the fields that are returned by a non-verifiable server evaluate -pub struct NonVerifiableServerEvaluateResult { +pub struct NonVerifiableServerEvaluateResult { /// The message to send to the client - pub message: EvaluationElement, -} - -/// Contains the fields that are returned by a non-verifiable client finalize -pub struct NonVerifiableClientFinalizeResult { - /// The output of the protocol - pub output: GenericArray::OutputSize>, + pub message: EvaluationElement, } /// Contains the fields that are returned by a verifiable client blind -pub struct VerifiableClientBlindResult { +pub struct VerifiableClientBlindResult { /// The state to be persisted on the client - pub state: VerifiableClient, + pub state: VerifiableClient, /// The message to send to the server - pub message: BlindedElement, + pub message: BlindedElement, } /// Contains the fields that are returned by a verifiable server evaluate -pub struct VerifiableServerEvaluateResult { +pub struct VerifiableServerEvaluateResult { /// The message to send to the client - pub message: EvaluationElement, + pub message: EvaluationElement, /// The proof for the client to verify - pub proof: Proof, + pub proof: Proof, } /// Contains the fields that are returned by a verifiable server batch evaluate -pub struct VerifiableServerBatchEvaluateResult { +pub struct VerifiableServerBatchEvaluateResult { /// The messages to send to the client - pub messages: Vec>, + pub messages: Vec>, /// The proof for the client to verify - pub proof: Proof, -} - -/// Contains the fields that are returned by a verifiable client finalize -pub struct VerifiableClientFinalizeResult { - /// The output of the protocol - pub output: GenericArray::OutputSize>, -} - -/// Contains the fields that are returned by a verifiable client batch finalize -pub struct VerifiableClientBatchFinalizeResult { - /// The output of the protocol - pub outputs: Vec::OutputSize>>, + pub proof: Proof, } /// An input to the verifiable client batch finalize function, constructed /// by aggregating clients and server messages -pub struct BatchFinalizeInput { - clients: Vec>, - messages: Vec>, +pub struct BatchFinalizeInput { + clients: Vec>, + messages: Vec>, } -impl BatchFinalizeInput { +impl BatchFinalizeInput { /// Create a new instance from a vector of clients and a vector of messages - pub fn new(clients: Vec>, messages: Vec>) -> Self { + pub fn new( + clients: Vec>, + messages: Vec>, + ) -> Self { Self { clients, messages } } } @@ -538,56 +547,56 @@ impl BatchFinalizeInput { /////////////////////////////////////////////// /// Convenience struct only used in batching APIs -struct BatchItems { - blind: ::Scalar, - evaluation_element: EvaluationElement, - blinded_element: BlindedElement, +struct BatchItems { + blind: ::Scalar, + evaluation_element: EvaluationElement, + blinded_element: BlindedElement, } // Inner function for blind. Returns the blind scalar and the blinded element -fn blind( +fn blind( input: &[u8], blinding_factor_rng: &mut R, mode: Mode, -) -> Result<(::Scalar, CS::Group), InternalError> { +) -> Result<(::Scalar, G), InternalError> { // Choose a random scalar that must be non-zero - let blind = ::random_nonzero_scalar(blinding_factor_rng); - let dst = [STR_HASH_TO_GROUP, &get_context_string::(mode)?].concat(); - let hashed_point = ::hash_to_curve::(input, &dst)?; + let blind = ::random_nonzero_scalar(blinding_factor_rng); + let dst = [STR_HASH_TO_GROUP, &get_context_string::(mode)?].concat(); + let hashed_point = ::hash_to_curve::(input, &dst)?; let blinded_element = hashed_point * &blind; Ok((blind, blinded_element)) } -fn verifiable_unblind( - batch_items: &[BatchItems], - pk: CS::Group, - proof: Proof, +fn verifiable_unblind( + batch_items: &[BatchItems], + pk: G, + proof: Proof, info: &[u8], -) -> Result, InternalError> { +) -> Result, InternalError> { let context = [ STR_CONTEXT, - &get_context_string::(Mode::Verifiable)?, + &get_context_string::(Mode::Verifiable)?, &serialize(info, 2)?, ] .concat(); let dst = [ STR_HASH_TO_SCALAR, - &get_context_string::(Mode::Verifiable)?, + &get_context_string::(Mode::Verifiable)?, ] .concat(); - let m = CS::Group::hash_to_scalar::(&context, &dst)?; + let m = G::hash_to_scalar::(&context, &dst)?; - let g = CS::Group::base_point(); + let g = G::base_point(); let t = g * &m; let u = t + &pk; - let blinds: Vec<::Scalar> = batch_items.iter().map(|x| x.blind).collect(); - let evaluation_elements: Vec> = batch_items + let blinds: Vec<::Scalar> = batch_items.iter().map(|x| x.blind).collect(); + let evaluation_elements: Vec> = batch_items .iter() .map(|x| x.evaluation_element.clone()) .collect(); - let blinded_elements: Vec> = batch_items + let blinded_elements: Vec> = batch_items .iter() .map(|x| x.blinded_element.clone()) .collect(); @@ -597,27 +606,27 @@ fn verifiable_unblind( let unblinded_elements = blinds .iter() .zip(evaluation_elements.iter()) - .map(|(&blind, x)| x.value * &CS::Group::scalar_invert(&blind)) + .map(|(&blind, x)| x.value * &G::scalar_invert(&blind)) .collect(); Ok(unblinded_elements) } #[allow(clippy::many_single_char_names)] -fn generate_proof( +fn generate_proof( rng: &mut R, - k: ::Scalar, - a: CS::Group, - b: CS::Group, - cs: &[EvaluationElement], - ds: &[BlindedElement], -) -> Result, InternalError> { - let (m, z) = compute_composites::(Some(k), b, cs, ds)?; + k: ::Scalar, + a: G, + b: G, + cs: &[EvaluationElement], + ds: &[BlindedElement], +) -> Result, InternalError> { + let (m, z) = compute_composites::(Some(k), b, cs, ds)?; - let r = CS::Group::random_nonzero_scalar(rng); + let r = G::random_nonzero_scalar(rng); let t2 = a * &r; let t3 = m * &r; - let challenge_dst = [STR_CHALLENGE, &get_context_string::(Mode::Verifiable)?].concat(); + let challenge_dst = [STR_CHALLENGE, &get_context_string::(Mode::Verifiable)?].concat(); let h2_input = [ serialize(&b.to_arr().to_vec(), 2)?, serialize(&m.to_arr().to_vec(), 2)?, @@ -630,29 +639,33 @@ fn generate_proof( let hash_to_scalar_dst = [ STR_HASH_TO_SCALAR, - &get_context_string::(Mode::Verifiable)?, + &get_context_string::(Mode::Verifiable)?, ] .concat(); - let c_scalar = CS::Group::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 { c_scalar, s_scalar }) + Ok(Proof { + c_scalar, + s_scalar, + hash: PhantomData, + }) } #[allow(clippy::many_single_char_names)] -fn verify_proof( - a: CS::Group, - b: CS::Group, - cs: &[EvaluationElement], - ds: &[BlindedElement], - proof: Proof, +fn verify_proof( + a: G, + b: G, + cs: &[EvaluationElement], + ds: &[BlindedElement], + proof: Proof, ) -> Result<(), InternalError> { - let (m, z) = compute_composites::(None, b, cs, ds)?; + let (m, z) = compute_composites::(None, b, cs, ds)?; let t2 = (a * &proof.s_scalar) + &(b * &proof.c_scalar); let t3 = (m * &proof.s_scalar) + &(z * &proof.c_scalar); - let challenge_dst = [STR_CHALLENGE, &get_context_string::(Mode::Verifiable)?].concat(); + let challenge_dst = [STR_CHALLENGE, &get_context_string::(Mode::Verifiable)?].concat(); let h2_input = [ serialize(&b.to_arr().to_vec(), 2)?, serialize(&m.to_arr().to_vec(), 2)?, @@ -665,29 +678,29 @@ fn verify_proof( let hash_to_scalar_dst = [ STR_HASH_TO_SCALAR, - &get_context_string::(Mode::Verifiable)?, + &get_context_string::(Mode::Verifiable)?, ] .concat(); - let c = CS::Group::hash_to_scalar::(&h2_input, &hash_to_scalar_dst)?; + let c = G::hash_to_scalar::(&h2_input, &hash_to_scalar_dst)?; - match CS::Group::ct_equal_scalar(&c, &proof.c_scalar) { + match G::ct_equal_scalar(&c, &proof.c_scalar) { true => Ok(()), false => Err(InternalError::ProofVerificationError), } } #[allow(clippy::type_complexity)] -fn finalize_after_unblind( - inputs_and_unblinded_elements: &[(Vec, CS::Group)], +fn finalize_after_unblind( + inputs_and_unblinded_elements: &[(Vec, G)], info: &[u8], mode: Mode, -) -> Result::OutputSize>>, InternalError> { - let finalize_dst = [STR_FINALIZE, &get_context_string::(mode)?].concat(); +) -> Result::OutputSize>>, InternalError> { + let finalize_dst = [STR_FINALIZE, &get_context_string::(mode)?].concat(); let mut outputs = vec![]; for (input, unblinded_element) in inputs_and_unblinded_elements { - outputs.push(::digest( + outputs.push(::digest( &[ serialize(input, 2)?, serialize(info, 2)?, @@ -701,28 +714,28 @@ fn finalize_after_unblind( Ok(outputs) } -fn compute_composites( - k_option: Option<::Scalar>, - b: CS::Group, - c_slice: &[EvaluationElement], - d_slice: &[BlindedElement], -) -> Result<(CS::Group, CS::Group), InternalError> { +fn compute_composites( + k_option: Option<::Scalar>, + b: G, + c_slice: &[EvaluationElement], + d_slice: &[BlindedElement], +) -> Result<(G, G), InternalError> { if c_slice.len() != d_slice.len() { return Err(InternalError::MismatchedLengthsForCompositeInputs); } - let seed_dst = [STR_SEED, &get_context_string::(Mode::Verifiable)?].concat(); - let composite_dst = [STR_COMPOSITE, &get_context_string::(Mode::Verifiable)?].concat(); + let seed_dst = [STR_SEED, &get_context_string::(Mode::Verifiable)?].concat(); + let composite_dst = [STR_COMPOSITE, &get_context_string::(Mode::Verifiable)?].concat(); let h1_input = [ serialize(&b.to_arr().to_vec(), 2)?, serialize(&seed_dst, 2)?, ] .concat(); - let seed = ::digest(&h1_input); + let seed = ::digest(&h1_input); - let mut m = CS::Group::identity(); - let mut z = CS::Group::identity(); + let mut m = G::identity(); + let mut z = G::identity(); for i in 0..c_slice.len() { let h2_input = [ @@ -735,10 +748,10 @@ fn compute_composites( .concat(); let dst = [ STR_HASH_TO_SCALAR, - &get_context_string::(Mode::Verifiable)?, + &get_context_string::(Mode::Verifiable)?, ] .concat(); - let di = CS::Group::hash_to_scalar::(&h2_input, &dst)?; + let di = G::hash_to_scalar::(&h2_input, &dst)?; m = c_slice[i].value * &di + &m; z = match k_option { Some(_) => z, @@ -756,11 +769,11 @@ fn compute_composites( /// Generates the contextString parameter as defined in /// -fn get_context_string(mode: Mode) -> Result, InternalError> { +fn get_context_string(mode: Mode) -> Result, InternalError> { Ok([ STR_VOPRF, &i2osp(mode as usize, 1)?, - &i2osp(CS::Group::SUITE_ID, 2)?, + &i2osp(G::SUITE_ID, 2)?, ] .concat()) } @@ -777,35 +790,35 @@ mod tests { use generic_array::GenericArray; use rand::rngs::OsRng; - fn prf( + fn prf( input: &[u8], - key: ::Scalar, + key: ::Scalar, info: &[u8], mode: Mode, - ) -> GenericArray::OutputSize> { - let dst = [STR_HASH_TO_GROUP, &get_context_string::(mode).unwrap()].concat(); - let point = CS::Group::hash_to_curve::(input, &dst).unwrap(); + ) -> GenericArray::OutputSize> { + let dst = [STR_HASH_TO_GROUP, &get_context_string::(mode).unwrap()].concat(); + let point = G::hash_to_curve::(input, &dst).unwrap(); let context = [ STR_CONTEXT, - &get_context_string::(mode).unwrap(), + &get_context_string::(mode).unwrap(), &serialize(info, 2).unwrap(), ] .concat(); - let dst = [STR_HASH_TO_SCALAR, &get_context_string::(mode).unwrap()].concat(); - let m = ::hash_to_scalar::(&context, &dst).unwrap(); + let dst = [STR_HASH_TO_SCALAR, &get_context_string::(mode).unwrap()].concat(); + let m = ::hash_to_scalar::(&context, &dst).unwrap(); - let res = point * &::scalar_invert(&(key + &m)); + let res = point * &::scalar_invert(&(key + &m)); - finalize_after_unblind::(&[(input.to_vec(), res)], info, mode).unwrap()[0].clone() + finalize_after_unblind::(&[(input.to_vec(), res)], info, mode).unwrap()[0].clone() } - fn base_retrieval() { + fn base_retrieval() { let input = b"input"; let info = b"info"; let mut rng = OsRng; - let client_blind_result = NonVerifiableClient::::blind(&input[..], &mut rng).unwrap(); - let server = NonVerifiableServer::::new(&mut rng).unwrap(); + let client_blind_result = NonVerifiableClient::::blind(&input[..], &mut rng).unwrap(); + let server = NonVerifiableServer::::new(&mut rng).unwrap(); let server_result = server .evaluate(client_blind_result.message, &Metadata(info.to_vec())) .unwrap(); @@ -813,16 +826,16 @@ mod tests { .state .finalize(server_result.message, &Metadata(info.to_vec())) .unwrap(); - let res2 = prf::(&input[..], server.get_private_key(), info, Mode::Base); - assert_eq!(client_finalize_result.output, res2); + let res2 = prf::(&input[..], server.get_private_key(), info, Mode::Base); + assert_eq!(client_finalize_result, res2); } - fn verifiable_retrieval() { + fn verifiable_retrieval() { let input = b"input"; let info = b"info"; let mut rng = OsRng; - let client_blind_result = VerifiableClient::::blind(&input[..], &mut rng).unwrap(); - let server = VerifiableServer::::new(&mut rng).unwrap(); + let client_blind_result = VerifiableClient::::blind(&input[..], &mut rng).unwrap(); + let server = VerifiableServer::::new(&mut rng).unwrap(); let server_result = server .evaluate( &mut rng, @@ -839,16 +852,16 @@ mod tests { &Metadata(info.to_vec()), ) .unwrap(); - let res2 = prf::(&input[..], server.get_private_key(), info, Mode::Verifiable); - assert_eq!(client_finalize_result.output, res2); + let res2 = prf::(&input[..], server.get_private_key(), info, Mode::Verifiable); + assert_eq!(client_finalize_result, res2); } - fn verifiable_bad_public_key() { + fn verifiable_bad_public_key() { let input = b"input"; let info = b"info"; let mut rng = OsRng; - let client_blind_result = VerifiableClient::::blind(&input[..], &mut rng).unwrap(); - let server = VerifiableServer::::new(&mut rng).unwrap(); + let client_blind_result = VerifiableClient::::blind(&input[..], &mut rng).unwrap(); + let server = VerifiableServer::::new(&mut rng).unwrap(); let server_result = server .evaluate( &mut rng, @@ -858,7 +871,7 @@ mod tests { .unwrap(); let wrong_pk = { // Choose a group element that is unlikely to be the right public key - CS::Group::hash_to_curve::(b"msg", b"dst").unwrap() + G::hash_to_curve::(b"msg", b"dst").unwrap() }; let client_finalize_result = client_blind_result.state.finalize( server_result.message, @@ -869,7 +882,7 @@ mod tests { assert!(client_finalize_result.is_err()); } - fn verifiable_batch_retrieval() { + fn verifiable_batch_retrieval() { let info = b"info"; let mut rng = OsRng; let mut inputs = vec![]; @@ -879,12 +892,13 @@ mod tests { for _ in 0..num_iterations { let mut input = vec![0u8; 32]; rng.fill_bytes(&mut input); - let client_blind_result = VerifiableClient::::blind(&input[..], &mut rng).unwrap(); + let client_blind_result = + VerifiableClient::::blind(&input[..], &mut rng).unwrap(); inputs.push(input); client_states.push(client_blind_result.state); client_messages.push(client_blind_result.message); } - let server = VerifiableServer::::new(&mut rng).unwrap(); + let server = VerifiableServer::::new(&mut rng).unwrap(); let server_result = server .batch_evaluate(&mut rng, &client_messages, &Metadata(info.to_vec())) .unwrap(); @@ -898,13 +912,13 @@ mod tests { .unwrap(); let mut res2 = vec![]; for input in inputs.iter().take(num_iterations) { - let output = prf::(&input[..], server.get_private_key(), info, Mode::Verifiable); + let output = prf::(&input[..], server.get_private_key(), info, Mode::Verifiable); res2.push(output); } - assert_eq!(client_finalize_result.outputs, res2); + assert_eq!(client_finalize_result, res2); } - fn verifiable_batch_bad_public_key() { + fn verifiable_batch_bad_public_key() { let info = b"info"; let mut rng = OsRng; let mut inputs = vec![]; @@ -914,19 +928,20 @@ mod tests { for _ in 0..num_iterations { let mut input = vec![0u8; 32]; rng.fill_bytes(&mut input); - let client_blind_result = VerifiableClient::::blind(&input[..], &mut rng).unwrap(); + let client_blind_result = + VerifiableClient::::blind(&input[..], &mut rng).unwrap(); inputs.push(input); client_states.push(client_blind_result.state); client_messages.push(client_blind_result.message); } - let server = VerifiableServer::::new(&mut rng).unwrap(); + let server = VerifiableServer::::new(&mut rng).unwrap(); let server_result = server .batch_evaluate(&mut rng, &client_messages, &Metadata(info.to_vec())) .unwrap(); let batch_finalize_input = BatchFinalizeInput::new(client_states, server_result.messages); let wrong_pk = { // Choose a group element that is unlikely to be the right public key - CS::Group::hash_to_curve::(b"msg", b"dst").unwrap() + G::hash_to_curve::(b"msg", b"dst").unwrap() }; let client_finalize_result = VerifiableClient::batch_finalize( batch_finalize_input, @@ -937,17 +952,18 @@ mod tests { assert!(client_finalize_result.is_err()); } - fn base_inversion_unsalted() { + fn base_inversion_unsalted() { let mut rng = OsRng; let mut input = alloc::vec![0u8; 64]; rng.fill_bytes(&mut input); let info = b"info"; - let client_blind_result = NonVerifiableClient::::blind(&input, &mut rng).unwrap(); + let client_blind_result = NonVerifiableClient::::blind(&input, &mut rng).unwrap(); let client_finalize_result = client_blind_result .state .finalize( EvaluationElement { value: client_blind_result.message.value, + hash: PhantomData, }, &Metadata(info.to_vec()), ) @@ -955,38 +971,40 @@ mod tests { let dst = [ STR_HASH_TO_GROUP, - &get_context_string::(Mode::Base).unwrap(), + &get_context_string::(Mode::Base).unwrap(), ] .concat(); - let point = CS::Group::hash_to_curve::(&input, &dst).unwrap(); - let res2 = finalize_after_unblind::(&[(input.to_vec(), point)], info, Mode::Base) + let point = G::hash_to_curve::(&input, &dst).unwrap(); + let res2 = finalize_after_unblind::(&[(input.to_vec(), point)], info, Mode::Base) .unwrap()[0] .clone(); - assert_eq!(client_finalize_result.output, res2); + assert_eq!(client_finalize_result, res2); } #[test] fn test_functionality() -> Result<(), InternalError> { - use crate::tests::Ristretto255Sha512; + use curve25519_dalek::ristretto::RistrettoPoint; + use sha2::Sha512; - base_retrieval::(); - base_inversion_unsalted::(); - verifiable_retrieval::(); - verifiable_batch_retrieval::(); - verifiable_bad_public_key::(); - verifiable_batch_bad_public_key::(); + base_retrieval::(); + base_inversion_unsalted::(); + verifiable_retrieval::(); + verifiable_batch_retrieval::(); + verifiable_bad_public_key::(); + verifiable_batch_bad_public_key::(); #[cfg(feature = "p256")] { - use crate::tests::P256Sha256; + use p256_::ProjectivePoint; + use sha2::Sha256; - base_retrieval::(); - base_inversion_unsalted::(); - verifiable_retrieval::(); - verifiable_batch_retrieval::(); - verifiable_bad_public_key::(); - verifiable_batch_bad_public_key::(); + base_retrieval::(); + base_inversion_unsalted::(); + verifiable_retrieval::(); + verifiable_batch_retrieval::(); + verifiable_bad_public_key::(); + verifiable_batch_bad_public_key::(); } Ok(())