Remove CipherSuite (#20)
* Remove `Hash` * Remove `CipherSuite` * Remove single field `struct`s
This commit is contained in:
@@ -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;
|
||||
}
|
||||
+1
-2
@@ -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<Vec<u8>, InternalError> {
|
||||
|
||||
/// Corresponds to the expand_message_xmd() function defined in
|
||||
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt>
|
||||
pub fn expand_message_xmd<H: Hash>(
|
||||
pub fn expand_message_xmd<H: BlockInput + Digest>(
|
||||
msg: &[u8],
|
||||
dst: &[u8],
|
||||
len_in_bytes: usize,
|
||||
|
||||
+7
-3
@@ -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<H: Hash>(msg: &[u8], dst: &[u8]) -> Result<Self, InternalError>;
|
||||
fn hash_to_curve<H: BlockInput + Digest>(msg: &[u8], dst: &[u8])
|
||||
-> Result<Self, InternalError>;
|
||||
|
||||
/// Hashes a slice of pseudo-random bytes to a scalar
|
||||
fn hash_to_scalar<H: Hash>(input: &[u8], dst: &[u8]) -> Result<Self::Scalar, InternalError>;
|
||||
fn hash_to_scalar<H: BlockInput + Digest>(
|
||||
input: &[u8],
|
||||
dst: &[u8],
|
||||
) -> Result<Self::Scalar, InternalError>;
|
||||
|
||||
/// The type of base field scalars
|
||||
type Scalar: Zeroize
|
||||
|
||||
+9
-3
@@ -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<H: Hash>(msg: &[u8], dst: &[u8]) -> Result<Self, InternalError> {
|
||||
fn hash_to_curve<H: BlockInput + Digest>(
|
||||
msg: &[u8],
|
||||
dst: &[u8],
|
||||
) -> Result<Self, InternalError> {
|
||||
// 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<BigInt> = 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<H: Hash>(input: &[u8], dst: &[u8]) -> Result<Self::Scalar, InternalError> {
|
||||
fn hash_to_scalar<H: BlockInput + Digest>(
|
||||
input: &[u8],
|
||||
dst: &[u8],
|
||||
) -> Result<Self::Scalar, InternalError> {
|
||||
// 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<BigInt> = Lazy::new(|| {
|
||||
|
||||
@@ -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<H: Hash>(msg: &[u8], dst: &[u8]) -> Result<Self, InternalError> {
|
||||
fn hash_to_curve<H: BlockInput + Digest>(
|
||||
msg: &[u8],
|
||||
dst: &[u8],
|
||||
) -> Result<Self, InternalError> {
|
||||
let uniform_bytes = super::expand::expand_message_xmd::<H>(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<H: Hash>(input: &[u8], dst: &[u8]) -> Result<Self::Scalar, InternalError> {
|
||||
fn hash_to_scalar<H: BlockInput + Digest>(
|
||||
input: &[u8],
|
||||
dst: &[u8],
|
||||
) -> Result<Self::Scalar, InternalError> {
|
||||
let uniform_bytes = super::expand::expand_message_xmd::<H>(input, dst, 64)?;
|
||||
|
||||
Ok(Scalar::from_bytes_mod_order_wide(
|
||||
|
||||
+12
-13
@@ -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::<Ristretto255Sha512>()?;
|
||||
test_zero_scalar_error::<Ristretto255Sha512>()?;
|
||||
test_identity_element_error::<RistrettoPoint>()?;
|
||||
test_zero_scalar_error::<RistrettoPoint>()?;
|
||||
|
||||
#[cfg(feature = "p256")]
|
||||
{
|
||||
use crate::tests::P256Sha256;
|
||||
use p256_::ProjectivePoint;
|
||||
|
||||
test_identity_element_error::<P256Sha256>()?;
|
||||
test_zero_scalar_error::<P256Sha256>()?;
|
||||
test_identity_element_error::<ProjectivePoint>()?;
|
||||
test_zero_scalar_error::<ProjectivePoint>()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Checks that the identity element cannot be deserialized
|
||||
fn test_identity_element_error<CS: CipherSuite>() -> Result<(), InternalError> {
|
||||
let identity = CS::Group::identity();
|
||||
let result = CS::Group::from_element_slice(&identity.to_arr());
|
||||
fn test_identity_element_error<G: Group>() -> 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<CS: CipherSuite>() -> 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<G: Group>() -> 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(())
|
||||
|
||||
-17
@@ -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<T: Update + BlockInput + FixedOutput + Reset + Default + Clone> Hash for T {}
|
||||
+50
-42
@@ -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<H: core::hash::Hasher>(&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<H: core::hash::Hasher>(&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<CS: CipherSuite> serde::Serialize for $t<CS> {
|
||||
impl$(<$($gen$(: $bound1$(+ $bound2)*)?),+>)? serde::Serialize for $name$(<$($gen),+>)? {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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<CS> {
|
||||
impl<'de$(, $($gen$(: $bound1$(+ $bound2)*)?),+)?> serde::Deserialize<'de> for $name$(<$($gen),+>)? {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
let s = <&str>::deserialize(deserializer)?;
|
||||
$t::<CS>::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<CS: CipherSuite> {
|
||||
marker: core::marker::PhantomData<CS>,
|
||||
}
|
||||
impl<'de, CS: CipherSuite> serde::de::Visitor<'de> for ByteVisitor<CS> {
|
||||
type Value = $t<CS>;
|
||||
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::<CS>::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::<CS> {
|
||||
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)*)?),+>)?);
|
||||
}
|
||||
}
|
||||
|
||||
+48
-99
@@ -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::<Default>::new(&mut server_rng)
|
||||
//! let server = NonVerifiableServer::<Group, Hash>::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::<Default>::blind(
|
||||
//! let client_blind_result = NonVerifiableClient::<Group, Hash>::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::<Default>::blind(
|
||||
//! # let client_blind_result = NonVerifiableClient::<Group, Hash>::blind(
|
||||
//! # b"input",
|
||||
//! # &mut client_rng,
|
||||
//! # ).expect("Unable to construct client");
|
||||
//! # use voprf::NonVerifiableServer;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let server = NonVerifiableServer::<Default>::new(&mut server_rng)
|
||||
//! # let server = NonVerifiableServer::<Group, Hash>::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::<Default>::blind(
|
||||
//! # let client_blind_result = NonVerifiableClient::<Group, Hash>::blind(
|
||||
//! # b"input",
|
||||
//! # &mut client_rng,
|
||||
//! # ).expect("Unable to construct client");
|
||||
//! # use voprf::NonVerifiableServer;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let server = NonVerifiableServer::<Default>::new(&mut server_rng)
|
||||
//! # let server = NonVerifiableServer::<Group, Hash>::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::<Default>::new(&mut server_rng)
|
||||
//! let server = VerifiableServer::<Group, Hash>::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::<Default>::blind(
|
||||
//! let client_blind_result = VerifiableClient::<Group, Hash>::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::<Default>::blind(
|
||||
//! # let client_blind_result = VerifiableClient::<Group, Hash>::blind(
|
||||
//! # b"input",
|
||||
//! # &mut client_rng,
|
||||
//! # ).expect("Unable to construct client");
|
||||
//! # use voprf::VerifiableServer;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let server = VerifiableServer::<Default>::new(&mut server_rng)
|
||||
//! # let server = VerifiableServer::<Group, Hash>::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::<Default>::blind(
|
||||
//! # let client_blind_result = VerifiableClient::<Group, Hash>::blind(
|
||||
//! # b"input",
|
||||
//! # &mut client_rng,
|
||||
//! # ).expect("Unable to construct client");
|
||||
//! # use voprf::VerifiableServer;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let server = VerifiableServer::<Default>::new(&mut server_rng)
|
||||
//! # let server = VerifiableServer::<Group, Hash>::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::<Default>::blind(
|
||||
//! let client_blind_result = VerifiableClient::<Group, Hash>::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::<Default>::blind(
|
||||
//! # let client_blind_result = VerifiableClient::<Group, Hash>::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::<Default>::new(&mut server_rng)
|
||||
//! # let server = VerifiableServer::<Group, Hash>::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::<Default>::blind(
|
||||
//! # let client_blind_result = VerifiableClient::<Group, Hash>::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::<Default>::new(&mut server_rng)
|
||||
//! # let server = VerifiableServer::<Group, Hash>::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,
|
||||
};
|
||||
|
||||
+50
-38
@@ -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<CS: CipherSuite> NonVerifiableClient<CS> {
|
||||
impl<G: Group, H: BlockInput + Digest> NonVerifiableClient<G, H> {
|
||||
/// Serialization into bytes
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
[
|
||||
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<Self, InternalError> {
|
||||
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
|
||||
let scalar_len = <G as Group>::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<CS: CipherSuite> VerifiableClient<CS> {
|
||||
impl<G: Group, H: BlockInput + Digest> VerifiableClient<G, H> {
|
||||
/// Serialization into bytes
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
[
|
||||
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<CS: CipherSuite> VerifiableClient<CS> {
|
||||
|
||||
/// Deserialization from bytes
|
||||
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
|
||||
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
|
||||
let elem_len = <CS::Group as Group>::ElemLen::USIZE;
|
||||
let scalar_len = <G as Group>::ScalarLen::USIZE;
|
||||
let elem_len = <G as Group>::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<CS: CipherSuite> VerifiableClient<CS> {
|
||||
blind,
|
||||
blinded_element,
|
||||
data,
|
||||
hash: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<CS: CipherSuite> NonVerifiableServer<CS> {
|
||||
impl<G: Group, H: BlockInput + Digest> NonVerifiableServer<G, H> {
|
||||
/// Serialization into bytes
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
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<Self, InternalError> {
|
||||
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
|
||||
let scalar_len = <G as Group>::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<CS: CipherSuite> VerifiableServer<CS> {
|
||||
impl<G: Group, H: BlockInput + Digest> VerifiableServer<G, H> {
|
||||
/// Serialization into bytes
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
[
|
||||
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<CS: CipherSuite> VerifiableServer<CS> {
|
||||
|
||||
/// Deserialization from bytes
|
||||
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
|
||||
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
|
||||
let elem_len = <CS::Group as Group>::ElemLen::USIZE;
|
||||
let scalar_len = <G as Group>::ScalarLen::USIZE;
|
||||
let elem_len = <G as Group>::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<CS: CipherSuite> Proof<CS> {
|
||||
impl<G: Group, H: BlockInput + Digest> Proof<G, H> {
|
||||
/// Serialization into bytes
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
[
|
||||
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<Self, InternalError> {
|
||||
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
|
||||
let scalar_len = <G as Group>::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<CS: CipherSuite> BlindedElement<CS> {
|
||||
impl<G: Group, H: BlockInput + Digest> BlindedElement<G, H> {
|
||||
/// Serialization into bytes
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
self.value.to_arr().to_vec()
|
||||
@@ -158,12 +168,13 @@ impl<CS: CipherSuite> BlindedElement<CS> {
|
||||
/// Deserialization from bytes
|
||||
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
|
||||
Ok(Self {
|
||||
value: CS::Group::from_element_slice(GenericArray::from_slice(input))?,
|
||||
value: G::from_element_slice(GenericArray::from_slice(input))?,
|
||||
hash: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<CS: CipherSuite> EvaluationElement<CS> {
|
||||
impl<G: Group, H: BlockInput + Digest> EvaluationElement<G, H> {
|
||||
/// Serialization into bytes
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
self.value.to_arr().to_vec()
|
||||
@@ -172,7 +183,8 @@ impl<CS: CipherSuite> EvaluationElement<CS> {
|
||||
/// Deserialization from bytes
|
||||
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
|
||||
Ok(Self {
|
||||
value: CS::Group::from_element_slice(GenericArray::from_slice(input))?,
|
||||
value: G::from_element_slice(GenericArray::from_slice(input))?,
|
||||
hash: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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::<Ristretto255Sha512>(&ristretto_base_tvs)?;
|
||||
test_base_blind::<Ristretto255Sha512>(&ristretto_base_tvs)?;
|
||||
test_base_evaluate::<Ristretto255Sha512>(&ristretto_base_tvs)?;
|
||||
test_base_finalize::<Ristretto255Sha512>(&ristretto_base_tvs)?;
|
||||
test_base_seed_to_key::<RistrettoPoint, Sha512>(&ristretto_base_tvs)?;
|
||||
test_base_blind::<RistrettoPoint, Sha512>(&ristretto_base_tvs)?;
|
||||
test_base_evaluate::<RistrettoPoint, Sha512>(&ristretto_base_tvs)?;
|
||||
test_base_finalize::<RistrettoPoint, Sha512>(&ristretto_base_tvs)?;
|
||||
|
||||
test_verifiable_seed_to_key::<Ristretto255Sha512>(&ristretto_verifiable_tvs)?;
|
||||
test_verifiable_blind::<Ristretto255Sha512>(&ristretto_verifiable_tvs)?;
|
||||
test_verifiable_evaluate::<Ristretto255Sha512>(&ristretto_verifiable_tvs)?;
|
||||
test_verifiable_finalize::<Ristretto255Sha512>(&ristretto_verifiable_tvs)?;
|
||||
test_verifiable_seed_to_key::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
||||
test_verifiable_blind::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
||||
test_verifiable_evaluate::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
||||
test_verifiable_finalize::<RistrettoPoint, Sha512>(&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::<P256Sha256>(&p256_base_tvs)?;
|
||||
test_base_blind::<P256Sha256>(&p256_base_tvs)?;
|
||||
test_base_evaluate::<P256Sha256>(&p256_base_tvs)?;
|
||||
test_base_finalize::<P256Sha256>(&p256_base_tvs)?;
|
||||
test_base_seed_to_key::<ProjectivePoint, Sha256>(&p256_base_tvs)?;
|
||||
test_base_blind::<ProjectivePoint, Sha256>(&p256_base_tvs)?;
|
||||
test_base_evaluate::<ProjectivePoint, Sha256>(&p256_base_tvs)?;
|
||||
test_base_finalize::<ProjectivePoint, Sha256>(&p256_base_tvs)?;
|
||||
|
||||
test_verifiable_seed_to_key::<P256Sha256>(&p256_verifiable_tvs)?;
|
||||
test_verifiable_blind::<P256Sha256>(&p256_verifiable_tvs)?;
|
||||
test_verifiable_evaluate::<P256Sha256>(&p256_verifiable_tvs)?;
|
||||
test_verifiable_finalize::<P256Sha256>(&p256_verifiable_tvs)?;
|
||||
test_verifiable_seed_to_key::<ProjectivePoint, Sha256>(&p256_verifiable_tvs)?;
|
||||
test_verifiable_blind::<ProjectivePoint, Sha256>(&p256_verifiable_tvs)?;
|
||||
test_verifiable_evaluate::<ProjectivePoint, Sha256>(&p256_verifiable_tvs)?;
|
||||
test_verifiable_finalize::<ProjectivePoint, Sha256>(&p256_verifiable_tvs)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn test_base_seed_to_key<CS: CipherSuite>(
|
||||
fn test_base_seed_to_key<G: Group, H: BlockInput + Digest>(
|
||||
tvs: &[VOPRFTestVectorParameters],
|
||||
) -> Result<(), InternalError> {
|
||||
for parameters in tvs {
|
||||
let server = NonVerifiableServer::<CS>::new_from_seed(¶meters.seed)?;
|
||||
let server = NonVerifiableServer::<G, H>::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<CS: CipherSuite>(
|
||||
fn test_verifiable_seed_to_key<G: Group, H: BlockInput + Digest>(
|
||||
tvs: &[VOPRFTestVectorParameters],
|
||||
) -> Result<(), InternalError> {
|
||||
for parameters in tvs {
|
||||
let server = VerifiableServer::<CS>::new_from_seed(¶meters.seed)?;
|
||||
let server = VerifiableServer::<G, H>::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<CS: CipherSuite>(
|
||||
}
|
||||
|
||||
// Tests input -> blind, blinded_element
|
||||
fn test_base_blind<CS: CipherSuite>(
|
||||
fn test_base_blind<G: Group, H: BlockInput + Digest>(
|
||||
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::<CS>::blind(¶meters.input[i], &mut rng)?;
|
||||
let client_result = NonVerifiableClient::<G, H>::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<CS: CipherSuite>(
|
||||
}
|
||||
|
||||
// Tests input -> blind, blinded_element
|
||||
fn test_verifiable_blind<CS: CipherSuite>(
|
||||
fn test_verifiable_blind<G: Group, H: BlockInput + Digest>(
|
||||
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::<CS>::blind(¶meters.input[i], &mut rng)?;
|
||||
VerifiableClient::<G, H>::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<CS: CipherSuite>(
|
||||
}
|
||||
|
||||
// Tests sksm, blinded_element -> evaluation_element
|
||||
fn test_base_evaluate<CS: CipherSuite>(
|
||||
fn test_base_evaluate<G: Group, H: BlockInput + Digest>(
|
||||
tvs: &[VOPRFTestVectorParameters],
|
||||
) -> Result<(), InternalError> {
|
||||
for parameters in tvs {
|
||||
for i in 0..parameters.input.len() {
|
||||
let server = NonVerifiableServer::<CS>::new_with_key(¶meters.sksm)?;
|
||||
let server = NonVerifiableServer::<G, H>::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<CS: CipherSuite>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn test_verifiable_evaluate<CS: CipherSuite>(
|
||||
fn test_verifiable_evaluate<G: Group, H: BlockInput + Digest>(
|
||||
tvs: &[VOPRFTestVectorParameters],
|
||||
) -> Result<(), InternalError> {
|
||||
for parameters in tvs {
|
||||
let mut rng = CycleRng::new(parameters.proof_random_scalar.clone());
|
||||
let server = VerifiableServer::<CS>::new_with_key(¶meters.sksm)?;
|
||||
let server = VerifiableServer::<G, H>::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<CS: CipherSuite>(
|
||||
}
|
||||
|
||||
// Tests input, blind, evaluation_element -> output
|
||||
fn test_base_finalize<CS: CipherSuite>(
|
||||
fn test_base_finalize<G: Group, H: BlockInput + Digest>(
|
||||
tvs: &[VOPRFTestVectorParameters],
|
||||
) -> Result<(), InternalError> {
|
||||
for parameters in tvs {
|
||||
for i in 0..parameters.input.len() {
|
||||
let client = NonVerifiableClient::<CS>::from_data_and_blind(
|
||||
let client = NonVerifiableClient::<G, H>::from_data_and_blind(
|
||||
¶meters.input[i],
|
||||
<CS::Group as Group>::from_scalar_slice(&GenericArray::clone_from_slice(
|
||||
<G as Group>::from_scalar_slice(&GenericArray::clone_from_slice(
|
||||
¶meters.blind[i],
|
||||
))?,
|
||||
);
|
||||
@@ -279,27 +281,24 @@ fn test_base_finalize<CS: CipherSuite>(
|
||||
&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<CS: CipherSuite>(
|
||||
fn test_verifiable_finalize<G: Group, H: BlockInput + Digest>(
|
||||
tvs: &[VOPRFTestVectorParameters],
|
||||
) -> Result<(), InternalError> {
|
||||
for parameters in tvs {
|
||||
let mut clients = vec![];
|
||||
for i in 0..parameters.input.len() {
|
||||
let client = VerifiableClient::<CS>::from_data_and_blind(
|
||||
let client = VerifiableClient::<G, H>::from_data_and_blind(
|
||||
¶meters.input[i],
|
||||
<CS::Group as Group>::from_scalar_slice(&GenericArray::clone_from_slice(
|
||||
<G as Group>::from_scalar_slice(&GenericArray::clone_from_slice(
|
||||
¶meters.blind[i],
|
||||
))?,
|
||||
<CS::Group as Group>::from_element_slice(&GenericArray::clone_from_slice(
|
||||
<G as Group>::from_element_slice(&GenericArray::clone_from_slice(
|
||||
¶meters.blinded_element[i],
|
||||
))?,
|
||||
);
|
||||
@@ -318,14 +317,13 @@ fn test_verifiable_finalize<CS: CipherSuite>(
|
||||
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::<Vec<Vec<u8>>>()
|
||||
|
||||
+287
-269
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user