Files
voprf-vx/src/voprf.rs
T

1212 lines
41 KiB
Rust
Raw Normal View History

2021-09-09 01:56:54 -07:00
// Copyright (c) Facebook, Inc. and its affiliates.
//
2021-09-27 18:53:06 -07:00
// 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.
2021-09-09 01:56:54 -07:00
2021-09-15 17:49:31 -07:00
//! Contains the main VOPRF API
use crate::{
errors::InternalError,
group::Group,
2021-10-16 01:56:21 +02:00
util::{i2osp, serialize, serialize_owned},
};
2021-09-28 19:44:57 -07:00
use alloc::vec::Vec;
use core::convert::TryInto;
2021-10-06 00:53:18 +02:00
use core::marker::PhantomData;
use digest::{BlockInput, Digest};
use generic_array::sequence::Concat;
2021-10-11 02:51:12 +02:00
use generic_array::{
typenum::{U1, U11, U2},
2021-10-11 02:51:12 +02:00
GenericArray,
};
2021-10-14 20:09:00 +02:00
use rand_core::{CryptoRng, RngCore};
use subtle::ConstantTimeEq;
2021-09-09 01:56:54 -07:00
2021-09-15 17:49:31 -07:00
///////////////
// Constants //
// ========= //
///////////////
static STR_HASH_TO_SCALAR: &[u8; 13] = b"HashToScalar-";
static STR_HASH_TO_GROUP: &[u8; 12] = b"HashToGroup-";
static STR_FINALIZE: &[u8; 9] = b"Finalize-";
static STR_SEED: &[u8; 5] = b"Seed-";
static STR_CONTEXT: &[u8] = b"Context-";
static STR_COMPOSITE: &[u8; 10] = b"Composite-";
static STR_CHALLENGE: &[u8; 10] = b"Challenge-";
static STR_VOPRF: &[u8; 8] = b"VOPRF08-";
2021-09-15 17:49:31 -07:00
/// Determines the mode of operation (either base mode or
/// verifiable mode)
#[derive(Clone, Copy)]
2021-09-15 17:49:31 -07:00
enum Mode {
Base = 0,
Verifiable = 1,
}
////////////////////////////
// High-level API Structs //
// ====================== //
////////////////////////////
2021-09-09 01:56:54 -07:00
2021-10-11 02:51:12 +02:00
impl_traits_for! {
/// A client which engages with a [NonVerifiableServer]
/// in base mode, meaning that the OPRF outputs are not
/// verifiable.
pub struct NonVerifiableClient<G: Group, H: BlockInput + Digest> {
#[bind]
pub(crate) blind: <G as Group>::Scalar,
pub(crate) data: Vec<u8>,
#[pd]
pub(crate) hash: PhantomData<H>,
}
}
impl_traits_for! {
/// 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<G: Group, H: BlockInput + Digest> {
#[bind]
pub(crate) blind: <G as Group>::Scalar,
#[bind]
pub(crate) blinded_element: G,
pub(crate) data: Vec<u8>,
2021-10-11 02:51:12 +02:00
#[pd]
pub(crate) hash: PhantomData<H>,
}
}
impl_traits_for! {
/// A server which engages with a [NonVerifiableClient]
/// in base mode, meaning that the OPRF outputs are not
/// verifiable.
pub struct NonVerifiableServer<G: Group, H: BlockInput + Digest> {
#[bind]
pub(crate) sk: <G as Group>::Scalar,
#[pd]
pub(crate) hash: PhantomData<H>,
}
}
impl_traits_for! {
/// 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<G: Group, H: BlockInput + Digest> {
#[bind]
pub(crate) sk: <G as Group>::Scalar,
#[bind]
pub(crate) pk: G,
#[pd]
pub(crate) hash: PhantomData<H>,
}
}
impl_traits_for! {
/// A proof produced by a [VerifiableServer] that
/// the OPRF output matches against a server public key.
pub struct Proof<G: Group, H: BlockInput + Digest> {
#[bind]
pub(crate) c_scalar: <G as Group>::Scalar,
pub(crate) s_scalar: <G as Group>::Scalar,
#[pd]
pub(crate) hash: PhantomData<H>,
}
}
impl_traits_for! {
/// The first client message sent from a client (either verifiable or not)
/// to a server (either verifiable or not).
pub struct BlindedElement<G: Group, H: BlockInput + Digest> {
#[bind]
pub(crate) value: G,
#[pd]
pub(crate) hash: PhantomData<H>,
}
}
impl_traits_for! {
/// 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<G: Group, H: BlockInput + Digest> {
#[bind]
pub(crate) value: G,
#[pd]
pub(crate) hash: PhantomData<H>,
}
}
2021-09-15 17:49:31 -07:00
/////////////////////////
// API Implementations //
// =================== //
/////////////////////////
2021-10-06 00:53:18 +02:00
impl<G: Group, H: BlockInput + Digest> NonVerifiableClient<G, H> {
2021-09-09 01:56:54 -07:00
/// Computes the first step for the multiplicative blinding version of DH-OPRF.
pub fn blind<R: RngCore + CryptoRng>(
input: Vec<u8>,
2021-09-09 01:56:54 -07:00
blinding_factor_rng: &mut R,
2021-10-06 00:53:18 +02:00
) -> Result<NonVerifiableClientBlindResult<G, H>, InternalError> {
let (blind, blinded_element) = blind::<G, H, _>(&input, blinding_factor_rng, Mode::Base)?;
2021-09-20 00:17:53 -07:00
Ok(NonVerifiableClientBlindResult {
state: Self {
data: input,
2021-09-09 01:56:54 -07:00
blind,
2021-10-06 00:53:18 +02:00
hash: PhantomData,
2021-09-09 01:56:54 -07:00
},
2021-09-28 19:44:57 -07:00
message: BlindedElement {
value: blinded_element,
2021-10-06 00:53:18 +02:00
hash: PhantomData,
2021-09-28 19:44:57 -07:00
},
2021-09-20 00:17:53 -07:00
})
2021-09-09 01:56:54 -07:00
}
#[cfg(feature = "danger")]
/// Computes the first step for the multiplicative blinding version of DH-OPRF,
/// taking a blinding factor scalar as input instead of sampling from an RNG.
///
/// # Caution
///
/// This should be used with caution, since
/// it does not perform any checks on the validity of the blinding factor!
pub fn deterministic_blind_unchecked(
input: Vec<u8>,
blind: <G as Group>::Scalar,
) -> Result<NonVerifiableClientBlindResult<G, H>, InternalError> {
let blinded_element = deterministic_blind_unchecked::<G, H>(&input, &blind, Mode::Base)?;
Ok(NonVerifiableClientBlindResult {
state: Self {
data: input,
blind,
hash: PhantomData,
},
message: BlindedElement {
value: blinded_element,
hash: PhantomData,
},
})
}
2021-09-09 01:56:54 -07:00
/// Computes the third step for the multiplicative blinding version of DH-OPRF, in which
/// the client unblinds the server's message.
pub fn finalize(
&self,
2021-10-06 00:53:18 +02:00
evaluation_element: EvaluationElement<G, H>,
metadata: Option<&[u8]>,
2021-10-06 00:53:18 +02:00
) -> Result<GenericArray<u8, <H as Digest>::OutputSize>, InternalError> {
2021-09-09 01:56:54 -07:00
let unblinded_element =
2021-10-06 00:53:18 +02:00
evaluation_element.value * &<G as Group>::scalar_invert(&self.blind);
let outputs = finalize_after_unblind::<G, H, _>(
Some((self.data.as_slice(), unblinded_element)).into_iter(),
metadata.unwrap_or_default(),
Mode::Base,
)?;
2021-10-06 00:53:18 +02:00
Ok(outputs[0].clone())
2021-09-09 01:56:54 -07:00
}
#[cfg(test)]
/// Only used for test functions
2021-10-06 00:53:18 +02:00
pub fn from_data_and_blind(data: &[u8], blind: <G as Group>::Scalar) -> Self {
2021-09-09 01:56:54 -07:00
Self {
data: data.to_vec(),
2021-10-06 00:19:20 +02:00
blind,
2021-10-06 00:53:18 +02:00
hash: PhantomData,
2021-09-09 01:56:54 -07:00
}
}
#[cfg(feature = "danger")]
/// Exposes the blind group element
2021-10-06 00:53:18 +02:00
pub fn get_blind(&self) -> <G as Group>::Scalar {
2021-09-09 01:56:54 -07:00
self.blind
}
}
2021-10-06 00:53:18 +02:00
impl<G: Group, H: BlockInput + Digest> VerifiableClient<G, H> {
/// Computes the first step for the multiplicative blinding version of DH-OPRF.
pub fn blind<R: RngCore + CryptoRng>(
input: Vec<u8>,
blinding_factor_rng: &mut R,
2021-10-06 00:53:18 +02:00
) -> Result<VerifiableClientBlindResult<G, H>, InternalError> {
let (blind, blinded_element) =
blind::<G, H, _>(&input, blinding_factor_rng, Mode::Verifiable)?;
2021-09-20 00:17:53 -07:00
Ok(VerifiableClientBlindResult {
state: Self {
data: input,
blind,
blinded_element,
2021-10-06 00:53:18 +02:00
hash: PhantomData,
},
2021-09-28 19:44:57 -07:00
message: BlindedElement {
value: blinded_element,
2021-10-06 00:53:18 +02:00
hash: PhantomData,
2021-09-28 19:44:57 -07:00
},
2021-09-20 00:17:53 -07:00
})
}
#[cfg(feature = "danger")]
/// Computes the first step for the multiplicative blinding version of DH-OPRF,
/// taking a blinding factor scalar as input instead of sampling from an RNG.
///
/// # Caution
///
/// This should be used with caution, since
/// it does not perform any checks on the validity of the blinding factor!
pub fn deterministic_blind_unchecked(
input: Vec<u8>,
blind: <G as Group>::Scalar,
) -> Result<VerifiableClientBlindResult<G, H>, InternalError> {
let blinded_element =
deterministic_blind_unchecked::<G, H>(&input, &blind, Mode::Verifiable)?;
Ok(VerifiableClientBlindResult {
state: Self {
data: input,
blind,
blinded_element,
hash: PhantomData,
},
message: BlindedElement {
value: blinded_element,
hash: PhantomData,
},
})
}
/// Computes the third step for the multiplicative blinding version of DH-OPRF, in which
/// the client unblinds the server's message.
pub fn finalize(
&self,
2021-10-06 00:53:18 +02:00
evaluation_element: EvaluationElement<G, H>,
proof: Proof<G, H>,
pk: G,
metadata: Option<&[u8]>,
2021-10-06 00:53:18 +02:00
) -> Result<GenericArray<u8, <H as Digest>::OutputSize>, InternalError> {
// circumvent `.clone()`
let clients: &[Self; 1] = core::slice::from_ref(self).try_into().unwrap();
let batch_result =
Self::batch_finalize(clients, &[evaluation_element], proof, pk, metadata)?;
2021-10-06 00:53:18 +02:00
Ok(batch_result[0].clone())
}
2021-09-15 17:49:31 -07:00
/// Allows for batching of the finalization of multiple [VerifiableClient] and [EvaluationElement] pairs
pub fn batch_finalize<'a, IC, IM>(
clients: &'a IC,
messages: &'a IM,
2021-10-06 00:53:18 +02:00
proof: Proof<G, H>,
pk: G,
metadata: Option<&[u8]>,
) -> Result<Vec<GenericArray<u8, <H as Digest>::OutputSize>>, InternalError>
where
G: 'a,
H: 'a,
&'a IC: 'a + IntoIterator<Item = &'a VerifiableClient<G, H>>,
<&'a IC as IntoIterator>::IntoIter: ExactSizeIterator,
&'a IM: 'a + IntoIterator<Item = &'a EvaluationElement<G, H>>,
<&'a IM as IntoIterator>::IntoIter: ExactSizeIterator,
{
struct Items<IC, IM> {
clients: IC,
messages: IM,
}
impl<'a, G: 'a + Group, H: 'a + BlockInput + Digest, IC: Copy, IM: Copy> IntoIterator
for &Items<IC, IM>
where
IC: IntoIterator<Item = &'a VerifiableClient<G, H>>,
<IC as IntoIterator>::IntoIter: ExactSizeIterator,
IM: IntoIterator<Item = &'a EvaluationElement<G, H>>,
<IM as IntoIterator>::IntoIter: ExactSizeIterator,
{
type Item = BatchItems<G, H>;
#[allow(clippy::type_complexity)]
type IntoIter = core::iter::Map<
core::iter::Zip<<IC as IntoIterator>::IntoIter, <IM as IntoIterator>::IntoIter>,
fn((&VerifiableClient<G, H>, &EvaluationElement<G, H>)) -> BatchItems<G, H>,
>;
fn into_iter(self) -> Self::IntoIter {
self.clients.into_iter().zip(self.messages.into_iter()).map(
|(client, evaluation_element)| BatchItems {
blind: client.blind,
evaluation_element: evaluation_element.copy(),
blinded_element: BlindedElement {
value: client.blinded_element,
hash: PhantomData,
},
},
)
}
}
let batch_items = Items { clients, messages };
let metadata = metadata.unwrap_or_default();
let unblinded_elements = verifiable_unblind(&batch_items, pk, proof, metadata)?;
let inputs_and_unblinded_elements = clients
.into_iter()
2021-09-20 00:17:53 -07:00
.zip(unblinded_elements.iter())
.map(|(client, &unblinded_element)| (client.data.as_slice(), unblinded_element));
finalize_after_unblind::<G, H, _>(inputs_and_unblinded_elements, metadata, Mode::Verifiable)
}
#[cfg(test)]
/// Only used for test functions
pub fn from_data_and_blind_and_element(
data: &[u8],
2021-10-06 00:53:18 +02:00
blind: <G as Group>::Scalar,
blinded_element: G,
) -> Self {
Self {
data: data.to_vec(),
2021-10-06 00:19:20 +02:00
blind,
blinded_element,
2021-10-06 00:53:18 +02:00
hash: PhantomData,
}
}
#[cfg(test)]
/// Only used for test functions
2021-10-06 00:53:18 +02:00
pub fn get_blind(&self) -> <G as Group>::Scalar {
self.blind
}
}
2021-10-06 00:53:18 +02:00
impl<G: Group, H: BlockInput + Digest> NonVerifiableServer<G, H> {
2021-09-15 17:49:31 -07:00
/// Produces a new instance of a [NonVerifiableServer] using a supplied RNG
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self, InternalError> {
let mut seed = GenericArray::<_, <H as Digest>::OutputSize>::default();
rng.fill_bytes(&mut seed);
Self::new_from_seed(&seed)
}
2021-09-15 17:49:31 -07:00
/// 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<Self, InternalError> {
let sk = G::from_scalar_slice(private_key_bytes)?;
2021-10-06 00:53:18 +02:00
Ok(Self {
sk,
hash: PhantomData,
})
}
2021-09-15 17:49:31 -07:00
/// Produces a new instance of a [NonVerifiableServer] using a supplied set of bytes which
/// are used as a seed to derive the server's private key.
///
/// Corresponds to DeriveKeyPair() function from the VOPRF specification.
pub fn new_from_seed(seed: &[u8]) -> Result<Self, InternalError> {
let dst =
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Base)?);
2021-10-16 01:56:21 +02:00
let sk = G::hash_to_scalar::<H, _, _>(Some(seed), dst)?;
2021-10-06 00:53:18 +02:00
Ok(Self {
sk,
hash: PhantomData,
})
}
// Only used for tests
#[cfg(test)]
2021-10-06 00:53:18 +02:00
pub fn get_private_key(&self) -> <G>::Scalar {
self.sk
}
/// Computes the second step for the multiplicative blinding version of DH-OPRF. This
/// message is sent from the server (who holds the OPRF key) to the client.
pub fn evaluate(
&self,
2021-10-06 00:53:18 +02:00
blinded_element: BlindedElement<G, H>,
metadata: Option<&[u8]>,
2021-10-06 00:53:18 +02:00
) -> Result<NonVerifiableServerEvaluateResult<G, H>, InternalError> {
2021-10-16 01:56:21 +02:00
chain!(
context,
STR_CONTEXT => |x| Some(x),
get_context_string::<G>(Mode::Base)? => |x| Some(x.as_slice()),
serialize::<U2>(metadata.unwrap_or_default())?,
);
let dst =
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Base)?);
2021-10-16 01:56:21 +02:00
let m = G::hash_to_scalar::<H, _, _>(context, dst)?;
let t = self.sk + &m;
2021-10-06 00:53:18 +02:00
let evaluation_element = blinded_element.value * &G::scalar_invert(&t);
2021-09-20 00:17:53 -07:00
Ok(NonVerifiableServerEvaluateResult {
2021-09-28 19:44:57 -07:00
message: EvaluationElement {
value: evaluation_element,
2021-10-06 00:53:18 +02:00
hash: PhantomData,
2021-09-28 19:44:57 -07:00
},
2021-09-20 00:17:53 -07:00
})
}
}
2021-10-06 00:53:18 +02:00
impl<G: Group, H: BlockInput + Digest> VerifiableServer<G, H> {
2021-09-15 17:49:31 -07:00
/// Produces a new instance of a [VerifiableServer] using a supplied RNG
2021-09-09 01:56:54 -07:00
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self, InternalError> {
let mut seed = GenericArray::<_, <H as Digest>::OutputSize>::default();
rng.fill_bytes(&mut seed);
Self::new_from_seed(&seed)
2021-09-09 01:56:54 -07:00
}
2021-09-15 17:49:31 -07:00
/// Produces a new instance of a [VerifiableServer] using a supplied set of bytes to
/// represent the server's private key
2021-09-09 01:56:54 -07:00
pub fn new_with_key(key: &[u8]) -> Result<Self, InternalError> {
let sk = G::from_scalar_slice(key)?;
2021-10-06 00:53:18 +02:00
let pk = G::base_point() * &sk;
Ok(Self {
sk,
pk,
hash: PhantomData,
})
}
2021-09-15 17:49:31 -07:00
/// Produces a new instance of a [VerifiableServer] using a supplied set of bytes which
/// are used as a seed to derive the server's private key.
///
/// Corresponds to DeriveKeyPair() function from the VOPRF specification.
pub fn new_from_seed(seed: &[u8]) -> Result<Self, InternalError> {
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
.concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
let sk = G::hash_to_scalar::<H, _, _>(Some(seed), dst)?;
2021-10-06 00:53:18 +02:00
let pk = G::base_point() * &sk;
Ok(Self {
sk,
pk,
hash: PhantomData,
})
2021-09-09 01:56:54 -07:00
}
// Only used for tests
#[cfg(test)]
2021-10-06 00:53:18 +02:00
pub fn get_private_key(&self) -> <G as Group>::Scalar {
self.sk
}
2021-09-09 01:56:54 -07:00
/// Computes the second step for the multiplicative blinding version of DH-OPRF. This
/// message is sent from the server (who holds the OPRF key) to the client.
pub fn evaluate<R: RngCore + CryptoRng>(
&self,
rng: &mut R,
2021-10-06 00:53:18 +02:00
blinded_element: BlindedElement<G, H>,
metadata: Option<&[u8]>,
2021-10-06 00:53:18 +02:00
) -> Result<VerifiableServerEvaluateResult<G, H>, InternalError> {
2021-09-20 00:17:53 -07:00
let batch_result = self.batch_evaluate(rng, &[blinded_element], metadata)?;
Ok(VerifiableServerEvaluateResult {
message: batch_result.messages[0].copy(),
2021-09-20 00:17:53 -07:00
proof: batch_result.proof,
})
}
2021-09-15 17:49:31 -07:00
/// Allows for batching of the evaluation of multiple [BlindedElement] messages from a [VerifiableClient]
pub fn batch_evaluate<'a, R: RngCore + CryptoRng, I>(
&self,
rng: &mut R,
blinded_elements: &'a I,
metadata: Option<&[u8]>,
) -> Result<VerifiableServerBatchEvaluateResult<G, H>, InternalError>
where
G: 'a,
H: 'a,
&'a I: IntoIterator<Item = &'a BlindedElement<G, H>>,
<&'a I as IntoIterator>::IntoIter: ExactSizeIterator,
{
2021-10-16 01:56:21 +02:00
chain!(context,
STR_CONTEXT => |x| Some(x),
get_context_string::<G>(Mode::Verifiable)? => |x| Some(x.as_slice()),
serialize::<U2>(metadata.unwrap_or_default())?,
);
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
.concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
let m = G::hash_to_scalar::<H, _, _>(context, dst)?;
let t = self.sk + &m;
2021-10-06 00:53:18 +02:00
let evaluation_elements: Vec<EvaluationElement<G, H>> = blinded_elements
.into_iter()
2021-09-28 19:44:57 -07:00
.map(|x| EvaluationElement {
2021-10-06 00:53:18 +02:00
value: x.value * &G::scalar_invert(&t),
hash: PhantomData,
2021-09-28 19:44:57 -07:00
})
.collect();
2021-10-06 00:53:18 +02:00
let g = G::base_point();
let u = g * &t;
let proof = generate_proof(
rng,
t,
g,
u,
evaluation_elements.iter().map(EvaluationElement::copy),
blinded_elements.into_iter().map(BlindedElement::copy),
)?;
2021-09-20 00:17:53 -07:00
Ok(VerifiableServerBatchEvaluateResult {
messages: evaluation_elements,
proof,
})
}
2021-09-15 17:49:31 -07:00
/// Retrieves the server's public key
2021-10-06 00:53:18 +02:00
pub fn get_public_key(&self) -> G {
self.pk
}
}
2021-09-20 00:17:53 -07:00
/////////////////////////
// Convenience Structs //
//==================== //
/////////////////////////
/// Contains the fields that are returned by a non-verifiable client blind
2021-10-06 00:53:18 +02:00
pub struct NonVerifiableClientBlindResult<G: Group, H: BlockInput + Digest> {
2021-09-20 00:17:53 -07:00
/// The state to be persisted on the client
2021-10-06 00:53:18 +02:00
pub state: NonVerifiableClient<G, H>,
2021-09-20 00:17:53 -07:00
/// The message to send to the server
2021-10-06 00:53:18 +02:00
pub message: BlindedElement<G, H>,
2021-09-20 00:17:53 -07:00
}
/// Contains the fields that are returned by a non-verifiable server evaluate
2021-10-06 00:53:18 +02:00
pub struct NonVerifiableServerEvaluateResult<G: Group, H: BlockInput + Digest> {
2021-09-20 00:17:53 -07:00
/// The message to send to the client
2021-10-06 00:53:18 +02:00
pub message: EvaluationElement<G, H>,
2021-09-20 00:17:53 -07:00
}
/// Contains the fields that are returned by a verifiable client blind
2021-10-06 00:53:18 +02:00
pub struct VerifiableClientBlindResult<G: Group, H: BlockInput + Digest> {
2021-09-20 00:17:53 -07:00
/// The state to be persisted on the client
2021-10-06 00:53:18 +02:00
pub state: VerifiableClient<G, H>,
2021-09-20 00:17:53 -07:00
/// The message to send to the server
2021-10-06 00:53:18 +02:00
pub message: BlindedElement<G, H>,
2021-09-20 00:17:53 -07:00
}
/// Contains the fields that are returned by a verifiable server evaluate
2021-10-06 00:53:18 +02:00
pub struct VerifiableServerEvaluateResult<G: Group, H: BlockInput + Digest> {
2021-09-20 00:17:53 -07:00
/// The message to send to the client
2021-10-06 00:53:18 +02:00
pub message: EvaluationElement<G, H>,
2021-09-20 00:17:53 -07:00
/// The proof for the client to verify
2021-10-06 00:53:18 +02:00
pub proof: Proof<G, H>,
2021-09-20 00:17:53 -07:00
}
/// Contains the fields that are returned by a verifiable server batch evaluate
2021-10-06 00:53:18 +02:00
pub struct VerifiableServerBatchEvaluateResult<G: Group, H: BlockInput + Digest> {
2021-09-20 00:17:53 -07:00
/// The messages to send to the client
2021-10-06 00:53:18 +02:00
pub messages: Vec<EvaluationElement<G, H>>,
2021-09-20 00:17:53 -07:00
/// The proof for the client to verify
2021-10-06 00:53:18 +02:00
pub proof: Proof<G, H>,
2021-09-20 00:17:53 -07:00
}
2021-09-15 17:49:31 -07:00
///////////////////////////////////////////////
// Inner functions and Trait Implementations //
// ========================================= //
///////////////////////////////////////////////
/// Convenience struct only used in batching APIs
2021-10-06 00:53:18 +02:00
struct BatchItems<G: Group, H: BlockInput + Digest> {
blind: <G as Group>::Scalar,
evaluation_element: EvaluationElement<G, H>,
blinded_element: BlindedElement<G, H>,
2021-09-15 17:49:31 -07:00
}
2021-10-11 02:51:12 +02:00
impl<G: Group, H: BlockInput + Digest> BlindedElement<G, H> {
/// Only used to easier validate allocation
fn copy(&self) -> Self {
Self {
value: self.value,
hash: PhantomData,
}
}
#[cfg(feature = "danger")]
/// Creates a [BlindedElement] from a raw group element.
///
/// # Caution
///
/// This should be used with caution, since
/// it does not perform any checks on the validity of the value itself!
pub fn from_value_unchecked(value: G) -> Self {
Self {
value,
hash: PhantomData,
}
}
#[cfg(feature = "danger")]
/// Exposes the internal value
pub fn value(&self) -> G {
self.value
2021-10-11 02:51:12 +02:00
}
}
impl<G: Group, H: BlockInput + Digest> EvaluationElement<G, H> {
/// Only used to easier validate allocation
fn copy(&self) -> Self {
Self {
value: self.value,
hash: PhantomData,
}
}
#[cfg(feature = "danger")]
/// Creates an [EvaluationElement] from a raw group element.
///
/// # Caution
///
/// This should be used with caution, since
/// it does not perform any checks on the validity of the value itself!
pub fn from_value_unchecked(value: G) -> Self {
Self {
value,
hash: PhantomData,
}
2021-10-11 02:51:12 +02:00
}
#[cfg(feature = "danger")]
/// Exposes the internal value
pub fn value(&self) -> G {
self.value
2021-10-11 02:51:12 +02:00
}
}
// Inner function for blind. Returns the blind scalar and the blinded element
2021-10-06 00:53:18 +02:00
fn blind<G: Group, H: BlockInput + Digest, R: RngCore + CryptoRng>(
input: &[u8],
blinding_factor_rng: &mut R,
mode: Mode,
2021-10-06 00:53:18 +02:00
) -> Result<(<G as Group>::Scalar, G), InternalError> {
// Choose a random scalar that must be non-zero
2021-10-06 00:53:18 +02:00
let blind = <G as Group>::random_nonzero_scalar(blinding_factor_rng);
let blinded_element = deterministic_blind_unchecked::<G, H>(input, &blind, mode)?;
Ok((blind, blinded_element))
}
// Inner function for blind that assumes that the blinding factor has already been chosen,
// and therefore takes it as input. Does not check if the blinding factor is non-zero.
fn deterministic_blind_unchecked<G: Group, H: BlockInput + Digest>(
input: &[u8],
blind: &<G as Group>::Scalar,
mode: Mode,
) -> Result<G, InternalError> {
let dst = GenericArray::from(*STR_HASH_TO_GROUP).concat(get_context_string::<G>(mode)?);
2021-10-14 20:09:00 +02:00
let hashed_point = <G as Group>::hash_to_curve::<H, _>(input, dst)?;
Ok(hashed_point * blind)
}
fn verifiable_unblind<'a, G: 'a + Group, H: 'a + BlockInput + Digest, I>(
batch_items: &'a I,
2021-10-06 00:53:18 +02:00
pk: G,
proof: Proof<G, H>,
2021-09-15 17:49:31 -07:00
info: &[u8],
) -> Result<Vec<G>, InternalError>
where
&'a I: IntoIterator<Item = BatchItems<G, H>>,
<&'a I as IntoIterator>::IntoIter: ExactSizeIterator,
{
2021-10-16 01:56:21 +02:00
chain!(context,
STR_CONTEXT => |x| Some(x),
get_context_string::<G>(Mode::Verifiable)? => |x| Some(x.as_slice()),
serialize::<U2>(info)?,
);
2021-09-15 17:49:31 -07:00
let dst =
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
let m = G::hash_to_scalar::<H, _, _>(context, dst)?;
2021-09-15 17:49:31 -07:00
2021-10-06 00:53:18 +02:00
let g = G::base_point();
2021-09-15 17:49:31 -07:00
let t = g * &m;
let u = t + &pk;
let blinds = batch_items.into_iter().map(|x| x.blind);
let evaluation_elements = batch_items.into_iter().map(|x| x.evaluation_element);
let blinded_elements = batch_items.into_iter().map(|x| x.blinded_element);
2021-09-15 17:49:31 -07:00
verify_proof(g, u, evaluation_elements, blinded_elements, proof)?;
2021-09-15 17:49:31 -07:00
let unblinded_elements = blinds
.zip(batch_items.into_iter().map(|x| x.evaluation_element))
.map(|(blind, x)| x.value * &G::scalar_invert(&blind))
2021-09-15 17:49:31 -07:00
.collect();
Ok(unblinded_elements)
}
#[allow(clippy::many_single_char_names)]
2021-10-06 00:53:18 +02:00
fn generate_proof<G: Group, H: BlockInput + Digest, R: RngCore + CryptoRng>(
rng: &mut R,
2021-10-06 00:53:18 +02:00
k: <G as Group>::Scalar,
a: G,
b: G,
cs: impl Iterator<Item = EvaluationElement<G, H>> + ExactSizeIterator,
ds: impl Iterator<Item = BlindedElement<G, H>> + ExactSizeIterator,
2021-10-06 00:53:18 +02:00
) -> Result<Proof<G, H>, InternalError> {
let (m, z) = compute_composites(Some(k), b, cs, ds)?;
2021-10-06 00:53:18 +02:00
let r = G::random_nonzero_scalar(rng);
let t2 = a * &r;
let t3 = m * &r;
let challenge_dst =
GenericArray::from(*STR_CHALLENGE).concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
chain!(
h2_input,
serialize_owned::<U2, _>(b.to_arr())?,
serialize_owned::<U2, _>(m.to_arr())?,
serialize_owned::<U2, _>(z.to_arr())?,
serialize_owned::<U2, _>(t2.to_arr())?,
serialize_owned::<U2, _>(t3.to_arr())?,
serialize_owned::<U2, _>(challenge_dst)?,
);
let hash_to_scalar_dst =
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
let c_scalar = G::hash_to_scalar::<H, _, _>(h2_input, hash_to_scalar_dst)?;
let s_scalar = r - &(c_scalar * &k);
2021-10-06 00:53:18 +02:00
Ok(Proof {
c_scalar,
s_scalar,
hash: PhantomData,
})
}
#[allow(clippy::many_single_char_names)]
2021-10-06 00:53:18 +02:00
fn verify_proof<G: Group, H: BlockInput + Digest>(
a: G,
b: G,
cs: impl Iterator<Item = EvaluationElement<G, H>> + ExactSizeIterator,
ds: impl Iterator<Item = BlindedElement<G, H>> + ExactSizeIterator,
2021-10-06 00:53:18 +02:00
proof: Proof<G, H>,
) -> Result<(), InternalError> {
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 =
GenericArray::from(*STR_CHALLENGE).concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
chain!(
h2_input,
serialize_owned::<U2, _>(b.to_arr())?,
serialize_owned::<U2, _>(m.to_arr())?,
serialize_owned::<U2, _>(z.to_arr())?,
serialize_owned::<U2, _>(t2.to_arr())?,
serialize_owned::<U2, _>(t3.to_arr())?,
serialize_owned::<U2, _>(challenge_dst)?,
);
let hash_to_scalar_dst =
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
let c = G::hash_to_scalar::<H, _, _>(h2_input, hash_to_scalar_dst)?;
2021-10-14 20:09:00 +02:00
match c.ct_eq(&proof.c_scalar).into() {
true => Ok(()),
false => Err(InternalError::ProofVerificationError),
2021-09-09 01:56:54 -07:00
}
}
fn finalize_after_unblind<
'a,
G: Group,
H: BlockInput + Digest,
I: Iterator<Item = (&'a [u8], G)>,
>(
inputs_and_unblinded_elements: I,
info: &[u8],
mode: Mode,
2021-10-06 00:53:18 +02:00
) -> Result<Vec<GenericArray<u8, <H as Digest>::OutputSize>>, InternalError> {
let finalize_dst = GenericArray::from(*STR_FINALIZE).concat(get_context_string::<G>(mode)?);
inputs_and_unblinded_elements
.map(|(input, unblinded_element)| {
2021-10-16 01:56:21 +02:00
chain!(
hash_input,
serialize::<U2>(input)?,
serialize::<U2>(info)?,
serialize_owned::<U2, _>(unblinded_element.to_arr())?,
serialize_owned::<U2, _>(finalize_dst)?,
);
Ok(hash_input
.fold(<H as Digest>::new(), |h, bytes| h.chain(bytes))
.finalize())
})
.collect()
}
2021-10-06 00:53:18 +02:00
fn compute_composites<G: Group, H: BlockInput + Digest>(
k_option: Option<<G as Group>::Scalar>,
b: G,
c_slice: impl Iterator<Item = EvaluationElement<G, H>> + ExactSizeIterator,
d_slice: impl Iterator<Item = BlindedElement<G, H>> + ExactSizeIterator,
2021-10-06 00:53:18 +02:00
) -> Result<(G, G), InternalError> {
if c_slice.len() != d_slice.len() {
return Err(InternalError::MismatchedLengthsForCompositeInputs);
}
let seed_dst = GenericArray::from(*STR_SEED).concat(get_context_string::<G>(Mode::Verifiable)?);
let composite_dst =
GenericArray::from(*STR_COMPOSITE).concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
chain!(
h1_input,
serialize_owned::<U2, _>(b.to_arr())?,
serialize_owned::<U2, _>(seed_dst)?,
);
let seed = h1_input
.fold(<H as Digest>::new(), |h, bytes| h.chain(bytes))
.finalize();
2021-10-06 00:53:18 +02:00
let mut m = G::identity();
let mut z = G::identity();
for (i, (c, d)) in c_slice.zip(d_slice).enumerate() {
2021-10-16 01:56:21 +02:00
chain!(h2_input,
serialize_owned::<U2, _>(seed.clone())?,
i2osp::<U2>(i)? => |x| Some(x.as_slice()),
serialize_owned::<U2, _>(c.value.to_arr())?,
serialize_owned::<U2, _>(d.value.to_arr())?,
serialize_owned::<U2, _>(composite_dst)?,
);
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
.concat(get_context_string::<G>(Mode::Verifiable)?);
2021-10-16 01:56:21 +02:00
let di = G::hash_to_scalar::<H, _, _>(h2_input, dst)?;
m = c.value * &di + &m;
z = match k_option {
Some(_) => z,
None => d.value * &di + &z,
};
}
z = match k_option {
Some(k) => m * &k,
None => z,
};
Ok((m, z))
2021-09-09 01:56:54 -07:00
}
2021-09-15 17:49:31 -07:00
/// Generates the contextString parameter as defined in
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html>
fn get_context_string<G: Group>(mode: Mode) -> Result<GenericArray<u8, U11>, InternalError> {
Ok(GenericArray::from(*STR_VOPRF)
.concat(i2osp::<U1>(mode as usize)?)
.concat(i2osp::<U2>(G::SUITE_ID)?))
2021-09-15 17:49:31 -07:00
}
2021-09-09 01:56:54 -07:00
///////////
// Tests //
// ===== //
///////////
2021-09-28 19:44:57 -07:00
2021-09-09 01:56:54 -07:00
#[cfg(test)]
mod tests {
use super::*;
use crate::group::Group;
use generic_array::GenericArray;
2021-09-09 01:56:54 -07:00
use rand::rngs::OsRng;
2021-10-11 02:51:12 +02:00
use zeroize::Zeroize;
2021-09-09 01:56:54 -07:00
2021-10-06 00:53:18 +02:00
fn prf<G: Group, H: BlockInput + Digest>(
input: &[u8],
2021-10-06 00:53:18 +02:00
key: <G as Group>::Scalar,
info: &[u8],
mode: Mode,
2021-10-06 00:53:18 +02:00
) -> GenericArray<u8, <H as Digest>::OutputSize> {
let dst =
GenericArray::from(*STR_HASH_TO_GROUP).concat(get_context_string::<G>(mode).unwrap());
2021-10-14 20:09:00 +02:00
let point = G::hash_to_curve::<H, _>(input, dst).unwrap();
2021-09-09 01:56:54 -07:00
2021-10-16 01:56:21 +02:00
chain!(context,
STR_CONTEXT => |x| Some(x),
get_context_string::<G>(mode).unwrap() => |x| Some(x.as_slice()),
serialize::<U2>(info).unwrap(),
);
let dst =
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(mode).unwrap());
2021-10-16 01:56:21 +02:00
let m = <G as Group>::hash_to_scalar::<H, _, _>(context, dst).unwrap();
2021-10-06 00:53:18 +02:00
let res = point * &<G as Group>::scalar_invert(&(key + &m));
finalize_after_unblind::<G, H, _>(Some((input, res)).into_iter(), info, mode).unwrap()[0]
.clone()
2021-09-09 01:56:54 -07:00
}
2021-10-06 00:53:18 +02:00
fn base_retrieval<G: Group, H: BlockInput + Digest>() {
let input = b"input";
let info = b"info";
2021-09-09 01:56:54 -07:00
let mut rng = OsRng;
let client_blind_result =
NonVerifiableClient::<G, H>::blind(input.to_vec(), &mut rng).unwrap();
2021-10-06 00:53:18 +02:00
let server = NonVerifiableServer::<G, H>::new(&mut rng).unwrap();
2021-09-20 00:17:53 -07:00
let server_result = server
.evaluate(client_blind_result.message, Some(info))
2021-09-20 00:17:53 -07:00
.unwrap();
let client_finalize_result = client_blind_result
.state
.finalize(server_result.message, Some(info))
2021-09-20 00:17:53 -07:00
.unwrap();
let res2 = prf::<G, H>(input, server.get_private_key(), info, Mode::Base);
2021-10-06 00:53:18 +02:00
assert_eq!(client_finalize_result, res2);
}
2021-10-06 00:53:18 +02:00
fn verifiable_retrieval<G: Group, H: BlockInput + Digest>() {
let input = b"input";
let info = b"info";
let mut rng = OsRng;
let client_blind_result =
VerifiableClient::<G, H>::blind(input.to_vec(), &mut rng).unwrap();
2021-10-06 00:53:18 +02:00
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
let server_result = server
.evaluate(&mut rng, client_blind_result.message, Some(info))
.unwrap();
let client_finalize_result = client_blind_result
.state
.finalize(
server_result.message,
server_result.proof,
server.get_public_key(),
Some(info),
)
.unwrap();
let res2 = prf::<G, H>(input, server.get_private_key(), info, Mode::Verifiable);
2021-10-06 00:53:18 +02:00
assert_eq!(client_finalize_result, res2);
2021-09-09 01:56:54 -07:00
}
2021-10-06 00:53:18 +02:00
fn verifiable_bad_public_key<G: Group, H: BlockInput + Digest>() {
let input = b"input";
let info = b"info";
let mut rng = OsRng;
let client_blind_result =
VerifiableClient::<G, H>::blind(input.to_vec(), &mut rng).unwrap();
2021-10-06 00:53:18 +02:00
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
let server_result = server
.evaluate(&mut rng, client_blind_result.message, Some(info))
.unwrap();
let wrong_pk = {
// Choose a group element that is unlikely to be the right public key
2021-10-14 20:09:00 +02:00
G::hash_to_curve::<H, _>(b"msg", (*b"dst").into()).unwrap()
};
let client_finalize_result = client_blind_result.state.finalize(
server_result.message,
server_result.proof,
wrong_pk,
Some(info),
);
assert!(client_finalize_result.is_err());
}
2021-10-06 00:53:18 +02:00
fn verifiable_batch_retrieval<G: Group, H: BlockInput + Digest>() {
let info = b"info";
let mut rng = OsRng;
let mut inputs = vec![];
let mut client_states = vec![];
let mut client_messages = vec![];
let num_iterations = 10;
for _ in 0..num_iterations {
let mut input = vec![0u8; 32];
rng.fill_bytes(&mut input);
2021-10-06 00:53:18 +02:00
let client_blind_result =
VerifiableClient::<G, H>::blind(input.clone(), &mut rng).unwrap();
inputs.push(input);
client_states.push(client_blind_result.state);
client_messages.push(client_blind_result.message);
}
2021-10-06 00:53:18 +02:00
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
let server_result = server
.batch_evaluate(&mut rng, &client_messages, Some(info))
.unwrap();
let client_finalize_result = VerifiableClient::batch_finalize(
&client_states,
&server_result.messages,
server_result.proof,
server.get_public_key(),
Some(info),
)
.unwrap();
let mut res2 = vec![];
2021-10-06 00:19:20 +02:00
for input in inputs.iter().take(num_iterations) {
let output = prf::<G, H>(input, server.get_private_key(), info, Mode::Verifiable);
res2.push(output);
}
2021-10-06 00:53:18 +02:00
assert_eq!(client_finalize_result, res2);
}
2021-10-06 00:53:18 +02:00
fn verifiable_batch_bad_public_key<G: Group, H: BlockInput + Digest>() {
let info = b"info";
let mut rng = OsRng;
let mut inputs = vec![];
let mut client_states = vec![];
let mut client_messages = vec![];
let num_iterations = 10;
for _ in 0..num_iterations {
let mut input = vec![0u8; 32];
rng.fill_bytes(&mut input);
2021-10-06 00:53:18 +02:00
let client_blind_result =
VerifiableClient::<G, H>::blind(input.clone(), &mut rng).unwrap();
inputs.push(input);
client_states.push(client_blind_result.state);
client_messages.push(client_blind_result.message);
}
2021-10-06 00:53:18 +02:00
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
let server_result = server
.batch_evaluate(&mut rng, &client_messages, Some(info))
.unwrap();
let wrong_pk = {
// Choose a group element that is unlikely to be the right public key
2021-10-14 20:09:00 +02:00
G::hash_to_curve::<H, _>(b"msg", (*b"dst").into()).unwrap()
};
let client_finalize_result = VerifiableClient::batch_finalize(
&client_states,
&server_result.messages,
server_result.proof,
wrong_pk,
Some(info),
);
assert!(client_finalize_result.is_err());
}
2021-10-06 00:53:18 +02:00
fn base_inversion_unsalted<G: Group, H: BlockInput + Digest>() {
2021-09-09 01:56:54 -07:00
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::<G, H>::blind(input.clone(), &mut rng).unwrap();
2021-09-20 00:17:53 -07:00
let client_finalize_result = client_blind_result
.state
.finalize(
2021-09-28 19:44:57 -07:00
EvaluationElement {
value: client_blind_result.message.value,
2021-10-06 00:53:18 +02:00
hash: PhantomData,
2021-09-28 19:44:57 -07:00
},
Some(info),
2021-09-20 00:17:53 -07:00
)
.unwrap();
2021-09-09 01:56:54 -07:00
let dst = GenericArray::from(*STR_HASH_TO_GROUP)
.concat(get_context_string::<G>(Mode::Base).unwrap());
2021-10-14 20:09:00 +02:00
let point = G::hash_to_curve::<H, _>(&input, dst).unwrap();
let res2 = finalize_after_unblind::<G, H, _>(
Some((input.as_slice(), point)).into_iter(),
info,
Mode::Base,
)
.unwrap()[0]
2021-09-28 19:44:57 -07:00
.clone();
2021-09-09 01:56:54 -07:00
2021-10-06 00:53:18 +02:00
assert_eq!(client_finalize_result, res2);
2021-09-09 01:56:54 -07:00
}
2021-09-28 19:44:57 -07:00
2021-10-11 02:51:12 +02:00
fn zeroize_base_client<G: Group, H: BlockInput + Digest>() {
let input = b"input";
let mut rng = OsRng;
let client_blind_result =
NonVerifiableClient::<G, H>::blind(input.to_vec(), &mut rng).unwrap();
2021-10-11 02:51:12 +02:00
let mut state = client_blind_result.state;
Zeroize::zeroize(&mut state);
assert!(state.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
let mut message = client_blind_result.message;
Zeroize::zeroize(&mut message);
assert!(message.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
}
fn zeroize_verifiable_client<G: Group, H: BlockInput + Digest>() {
let input = b"input";
let mut rng = OsRng;
let client_blind_result =
VerifiableClient::<G, H>::blind(input.to_vec(), &mut rng).unwrap();
2021-10-11 02:51:12 +02:00
let mut state = client_blind_result.state;
Zeroize::zeroize(&mut state);
assert!(state.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
let mut message = client_blind_result.message;
Zeroize::zeroize(&mut message);
assert!(message.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
}
fn zeroize_base_server<G: Group, H: BlockInput + Digest>() {
let input = b"input";
let info = b"info";
let mut rng = OsRng;
let client_blind_result =
NonVerifiableClient::<G, H>::blind(input.to_vec(), &mut rng).unwrap();
2021-10-11 02:51:12 +02:00
let server = NonVerifiableServer::<G, H>::new(&mut rng).unwrap();
let server_result = server
.evaluate(client_blind_result.message, Some(info))
2021-10-11 02:51:12 +02:00
.unwrap();
let mut state = server;
Zeroize::zeroize(&mut state);
assert!(state.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
let mut message = server_result.message;
Zeroize::zeroize(&mut message);
assert!(message.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
}
fn zeroize_verifiable_server<G: Group, H: BlockInput + Digest>() {
let input = b"input";
let info = b"info";
let mut rng = OsRng;
let client_blind_result =
VerifiableClient::<G, H>::blind(input.to_vec(), &mut rng).unwrap();
2021-10-11 02:51:12 +02:00
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
let server_result = server
.evaluate(&mut rng, client_blind_result.message, Some(info))
2021-10-11 02:51:12 +02:00
.unwrap();
let mut state = server;
Zeroize::zeroize(&mut state);
assert!(state.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
let mut message = server_result.message;
Zeroize::zeroize(&mut message);
assert!(message.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
let mut proof = server_result.proof;
Zeroize::zeroize(&mut proof);
assert!(proof.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
}
2021-09-28 19:44:57 -07:00
#[test]
fn test_functionality() -> Result<(), InternalError> {
2021-10-06 00:53:18 +02:00
use curve25519_dalek::ristretto::RistrettoPoint;
use sha2::Sha512;
2021-09-28 19:44:57 -07:00
2021-10-06 00:53:18 +02:00
base_retrieval::<RistrettoPoint, Sha512>();
base_inversion_unsalted::<RistrettoPoint, Sha512>();
verifiable_retrieval::<RistrettoPoint, Sha512>();
verifiable_batch_retrieval::<RistrettoPoint, Sha512>();
verifiable_bad_public_key::<RistrettoPoint, Sha512>();
verifiable_batch_bad_public_key::<RistrettoPoint, Sha512>();
2021-09-28 19:44:57 -07:00
2021-10-11 02:51:12 +02:00
zeroize_base_client::<RistrettoPoint, Sha512>();
zeroize_base_server::<RistrettoPoint, Sha512>();
zeroize_verifiable_client::<RistrettoPoint, Sha512>();
zeroize_verifiable_server::<RistrettoPoint, Sha512>();
2021-09-28 19:44:57 -07:00
#[cfg(feature = "p256")]
{
2021-10-06 00:53:18 +02:00
use p256_::ProjectivePoint;
use sha2::Sha256;
base_retrieval::<ProjectivePoint, Sha256>();
base_inversion_unsalted::<ProjectivePoint, Sha256>();
verifiable_retrieval::<ProjectivePoint, Sha256>();
verifiable_batch_retrieval::<ProjectivePoint, Sha256>();
verifiable_bad_public_key::<ProjectivePoint, Sha256>();
verifiable_batch_bad_public_key::<ProjectivePoint, Sha256>();
2021-10-11 02:51:12 +02:00
zeroize_base_client::<ProjectivePoint, Sha256>();
zeroize_base_server::<ProjectivePoint, Sha256>();
zeroize_verifiable_client::<ProjectivePoint, Sha256>();
zeroize_verifiable_server::<ProjectivePoint, Sha256>();
2021-09-28 19:44:57 -07:00
}
Ok(())
}
2021-09-09 01:56:54 -07:00
}