Files
voprf-vx/src/voprf.rs
T

1700 lines
60 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
2021-12-23 21:03:38 +01:00
#[cfg(feature = "alloc")]
2021-09-28 19:44:57 -07:00
use alloc::vec::Vec;
2021-12-23 21:03:38 +01:00
use core::iter::{self, Map, Repeat, Zip};
2021-12-23 01:17:03 +01:00
2021-12-21 20:17:02 +01:00
use derive_where::DeriveWhere;
2021-12-23 21:58:00 +01:00
use digest::core_api::BlockSizeUser;
2022-01-21 22:52:09 +01:00
use digest::{Digest, Output, OutputSizeUser};
use generic_array::sequence::Concat;
2022-01-21 22:52:09 +01:00
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U11, U20, U256};
2021-12-23 01:17:03 +01:00
use generic_array::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
2022-01-28 01:38:17 +01:00
#[cfg(feature = "serde")]
use crate::serialization::serde::{Element, Scalar};
2022-01-18 12:34:28 +01:00
use crate::util::{i2osp_2, i2osp_2_array};
2022-01-21 22:52:09 +01:00
use crate::{CipherSuite, Error, Group, Result};
2021-12-23 01:17:03 +01:00
2021-09-15 17:49:31 -07:00
///////////////
// Constants //
// ========= //
///////////////
2022-01-18 12:34:28 +01:00
const STR_FINALIZE: [u8; 9] = *b"Finalize-";
const STR_SEED: [u8; 5] = *b"Seed-";
const STR_CONTEXT: [u8; 8] = *b"Context-";
const STR_COMPOSITE: [u8; 10] = *b"Composite-";
const STR_CHALLENGE: [u8; 10] = *b"Challenge-";
const STR_VOPRF: [u8; 8] = *b"VOPRF08-";
2021-09-15 17:49:31 -07:00
2022-01-18 12:34:28 +01:00
/// Determines the mode of operation (either base mode or verifiable mode). This
/// is only used for custom implementations for [`Group`].
2022-01-28 01:38:17 +01:00
#[derive(Clone, Copy, Debug)]
2022-01-18 12:34:28 +01:00
pub enum Mode {
/// Non-verifiable mode.
Base,
/// Verifiable mode.
Verifiable,
}
impl Mode {
/// Mode as it is represented in a context string.
pub fn to_u8(self) -> u8 {
match self {
Mode::Base => 0,
Mode::Verifiable => 1,
}
}
2021-09-15 17:49:31 -07:00
}
////////////////////////////
// High-level API Structs //
// ====================== //
////////////////////////////
2021-09-09 01:56:54 -07:00
2021-12-23 01:17:03 +01:00
/// A client which engages with a [NonVerifiableServer] in base mode, meaning
/// that the OPRF outputs are not verifiable.
2021-12-21 20:17:02 +01:00
#[derive(DeriveWhere)]
#[derive_where(Clone, Zeroize(drop))]
2022-01-21 22:52:09 +01:00
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Scalar)]
2021-12-23 21:03:38 +01:00
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
2022-01-28 01:38:17 +01:00
serde(crate = "serde", bound = "")
2021-12-23 21:03:38 +01:00
)]
2022-01-21 22:52:09 +01:00
pub struct NonVerifiableClient<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-28 01:38:17 +01:00
#[cfg_attr(feature = "serde", serde(with = "Scalar::<CS::Group>"))]
2022-01-21 22:52:09 +01:00
pub(crate) blind: <CS::Group as Group>::Scalar,
2021-10-11 02:51:12 +02:00
}
2021-12-23 01:17:03 +01:00
/// A client which engages with a [VerifiableServer] in verifiable mode, meaning
/// that the OPRF outputs can be checked against a server public key.
2021-12-21 20:17:02 +01:00
#[derive(DeriveWhere)]
#[derive_where(Clone, Zeroize(drop))]
2022-01-21 22:52:09 +01:00
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Scalar, <CS::Group as Group>::Elem)]
2021-12-23 21:03:38 +01:00
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
2022-01-28 01:38:17 +01:00
serde(crate = "serde", bound = "")
2021-12-23 21:03:38 +01:00
)]
2022-01-21 22:52:09 +01:00
pub struct VerifiableClient<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-28 01:38:17 +01:00
#[cfg_attr(feature = "serde", serde(with = "Scalar::<CS::Group>"))]
2022-01-21 22:52:09 +01:00
pub(crate) blind: <CS::Group as Group>::Scalar,
2022-01-28 01:38:17 +01:00
#[cfg_attr(feature = "serde", serde(with = "Element::<CS::Group>"))]
2022-01-21 22:52:09 +01:00
pub(crate) blinded_element: <CS::Group as Group>::Elem,
2021-10-11 02:51:12 +02:00
}
2021-12-23 01:17:03 +01:00
/// A server which engages with a [NonVerifiableClient] in base mode, meaning
/// that the OPRF outputs are not verifiable.
2021-12-21 20:17:02 +01:00
#[derive(DeriveWhere)]
#[derive_where(Clone, Zeroize(drop))]
2022-01-21 22:52:09 +01:00
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Scalar)]
2021-12-23 21:03:38 +01:00
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
2022-01-28 01:38:17 +01:00
serde(crate = "serde", bound = "")
2021-12-23 21:03:38 +01:00
)]
2022-01-21 22:52:09 +01:00
pub struct NonVerifiableServer<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-28 01:38:17 +01:00
#[cfg_attr(feature = "serde", serde(with = "Scalar::<CS::Group>"))]
2022-01-21 22:52:09 +01:00
pub(crate) sk: <CS::Group as Group>::Scalar,
2021-10-11 02:51:12 +02:00
}
2021-12-23 01:17:03 +01:00
/// A server which engages with a [VerifiableClient] in verifiable mode, meaning
/// that the OPRF outputs can be checked against a server public key.
2021-12-21 20:17:02 +01:00
#[derive(DeriveWhere)]
#[derive_where(Clone, Zeroize(drop))]
2022-01-21 22:52:09 +01:00
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Scalar, <CS::Group as Group>::Elem)]
2021-12-23 21:03:38 +01:00
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
2022-01-28 01:38:17 +01:00
serde(crate = "serde", bound = "")
2021-12-23 21:03:38 +01:00
)]
2022-01-21 22:52:09 +01:00
pub struct VerifiableServer<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-28 01:38:17 +01:00
#[cfg_attr(feature = "serde", serde(with = "Scalar::<CS::Group>"))]
2022-01-21 22:52:09 +01:00
pub(crate) sk: <CS::Group as Group>::Scalar,
2022-01-28 01:38:17 +01:00
#[cfg_attr(feature = "serde", serde(with = "Element::<CS::Group>"))]
2022-01-21 22:52:09 +01:00
pub(crate) pk: <CS::Group as Group>::Elem,
2021-10-11 02:51:12 +02:00
}
2021-12-23 01:17:03 +01:00
/// A proof produced by a [VerifiableServer] that the OPRF output matches
/// against a server public key.
2021-12-21 20:17:02 +01:00
#[derive(DeriveWhere)]
#[derive_where(Clone, Zeroize(drop))]
2022-01-21 22:52:09 +01:00
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Scalar)]
2021-12-23 21:03:38 +01:00
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
2022-01-28 01:38:17 +01:00
serde(crate = "serde", bound = "")
2021-12-23 21:03:38 +01:00
)]
2022-01-21 22:52:09 +01:00
pub struct Proof<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-28 01:38:17 +01:00
#[cfg_attr(feature = "serde", serde(with = "Scalar::<CS::Group>"))]
2022-01-21 22:52:09 +01:00
pub(crate) c_scalar: <CS::Group as Group>::Scalar,
2022-01-28 01:38:17 +01:00
#[cfg_attr(feature = "serde", serde(with = "Scalar::<CS::Group>"))]
2022-01-21 22:52:09 +01:00
pub(crate) s_scalar: <CS::Group as Group>::Scalar,
2021-10-11 02:51:12 +02:00
}
2021-12-23 01:17:03 +01:00
/// The first client message sent from a client (either verifiable or not) to a
/// server (either verifiable or not).
2021-12-21 20:17:02 +01:00
#[derive(DeriveWhere)]
#[derive_where(Clone, Zeroize(drop))]
2022-01-21 22:52:09 +01:00
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Elem)]
2021-12-23 21:03:38 +01:00
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
2022-01-28 01:38:17 +01:00
serde(crate = "serde", bound = "")
2021-12-23 21:03:38 +01:00
)]
2022-01-28 01:38:17 +01:00
pub struct BlindedElement<CS: CipherSuite>(
#[cfg_attr(feature = "serde", serde(with = "Element::<CS::Group>"))]
pub(crate) <CS::Group as Group>::Elem,
)
2022-01-21 22:52:09 +01:00
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>;
2021-10-11 02:51:12 +02:00
2021-12-23 01:17:03 +01:00
/// The server's response to the [BlindedElement] message from a client (either
/// verifiable or not) to a server (either verifiable or not).
2021-12-21 20:17:02 +01:00
#[derive(DeriveWhere)]
#[derive_where(Clone, Zeroize(drop))]
2022-01-21 22:52:09 +01:00
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Elem)]
2021-12-23 21:03:38 +01:00
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
2022-01-28 01:38:17 +01:00
serde(crate = "serde", bound = "")
2021-12-23 21:03:38 +01:00
)]
2022-01-28 01:38:17 +01:00
pub struct EvaluationElement<CS: CipherSuite>(
#[cfg_attr(feature = "serde", serde(with = "Element::<CS::Group>"))]
pub(crate) <CS::Group as Group>::Elem,
)
2022-01-21 22:52:09 +01:00
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>;
2021-09-15 17:49:31 -07:00
/////////////////////////
// API Implementations //
// =================== //
/////////////////////////
2022-01-21 22:52:09 +01:00
impl<CS: CipherSuite> NonVerifiableClient<CS>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-12-23 01:17:03 +01:00
/// Computes the first step for the multiplicative blinding version of
/// DH-OPRF.
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Input`] if the `input` is empty or longer then [`u16::MAX`].
2021-09-09 01:56:54 -07:00
pub fn blind<R: RngCore + CryptoRng>(
2021-12-23 21:03:38 +01:00
input: &[u8],
2021-09-09 01:56:54 -07:00
blinding_factor_rng: &mut R,
2022-01-21 22:52:09 +01:00
) -> Result<NonVerifiableClientBlindResult<CS>> {
let (blind, blinded_element) = blind::<CS, _>(input, blinding_factor_rng, Mode::Base)?;
2021-09-20 00:17:53 -07:00
Ok(NonVerifiableClientBlindResult {
2022-01-21 22:52:09 +01:00
state: Self { blind },
message: BlindedElement(blinded_element),
2021-09-20 00:17:53 -07:00
})
2021-09-09 01:56:54 -07:00
}
2021-12-21 20:17:02 +01:00
#[cfg(any(feature = "danger", test))]
2021-12-23 01:17:03 +01:00
/// 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
///
2021-12-23 01:17:03 +01:00
/// This should be used with caution, since it does not perform any checks
/// on the validity of the blinding factor!
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Input`] if the `input` is empty or longer then [`u16::MAX`].
pub fn deterministic_blind_unchecked(
2021-12-23 21:03:38 +01:00
input: &[u8],
2022-01-21 22:52:09 +01:00
blind: <CS::Group as Group>::Scalar,
) -> Result<NonVerifiableClientBlindResult<CS>> {
let blinded_element = deterministic_blind_unchecked::<CS>(input, &blind, Mode::Base)?;
Ok(NonVerifiableClientBlindResult {
2022-01-21 22:52:09 +01:00
state: Self { blind },
message: BlindedElement(blinded_element),
})
}
2021-12-23 01:17:03 +01:00
/// Computes the third step for the multiplicative blinding version of
/// DH-OPRF, in which the client unblinds the server's message.
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// - [`Error::Input`] if the `input` is empty or longer then [`u16::MAX`].
/// - [`Error::Metadata`] if the `metadata` is longer then `u16::MAX - 21`.
2021-09-09 01:56:54 -07:00
pub fn finalize(
&self,
2021-12-23 21:03:38 +01:00
input: &[u8],
2022-01-21 22:52:09 +01:00
evaluation_element: &EvaluationElement<CS>,
metadata: Option<&[u8]>,
2022-01-21 22:52:09 +01:00
) -> Result<Output<CS::Hash>> {
let unblinded_element = evaluation_element.0 * &CS::Group::invert_scalar(self.blind);
let mut outputs = finalize_after_unblind::<CS, _, _>(
2022-01-25 05:55:02 +01:00
iter::once((input, unblinded_element)),
metadata.unwrap_or_default(),
Mode::Base,
2022-01-25 05:55:02 +01:00
);
2021-12-23 21:03:38 +01:00
outputs.next().unwrap()
2021-09-09 01:56:54 -07:00
}
#[cfg(test)]
/// Only used for test functions
2022-01-21 22:52:09 +01:00
pub fn from_blind(blind: <CS::Group as Group>::Scalar) -> Self {
Self { blind }
2021-09-09 01:56:54 -07:00
}
#[cfg(feature = "danger")]
/// Exposes the blind group element
2022-01-21 22:52:09 +01:00
pub fn get_blind(&self) -> <CS::Group as Group>::Scalar {
2021-09-09 01:56:54 -07:00
self.blind
}
}
2022-01-21 22:52:09 +01:00
impl<CS: CipherSuite> VerifiableClient<CS>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-12-23 01:17:03 +01:00
/// Computes the first step for the multiplicative blinding version of
/// DH-OPRF.
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Input`] if the `input` is empty or longer then [`u16::MAX`].
pub fn blind<R: RngCore + CryptoRng>(
2021-12-23 21:03:38 +01:00
input: &[u8],
blinding_factor_rng: &mut R,
2022-01-21 22:52:09 +01:00
) -> Result<VerifiableClientBlindResult<CS>> {
let (blind, blinded_element) =
2022-01-21 22:52:09 +01:00
blind::<CS, _>(input, blinding_factor_rng, Mode::Verifiable)?;
2021-09-20 00:17:53 -07:00
Ok(VerifiableClientBlindResult {
state: Self {
blind,
blinded_element,
2021-09-28 19:44:57 -07:00
},
2022-01-21 22:52:09 +01:00
message: BlindedElement(blinded_element),
2021-09-20 00:17:53 -07:00
})
}
2021-12-21 20:17:02 +01:00
#[cfg(any(feature = "danger", test))]
2021-12-23 01:17:03 +01:00
/// 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
///
2021-12-23 01:17:03 +01:00
/// This should be used with caution, since it does not perform any checks
/// on the validity of the blinding factor!
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Input`] if the `input` is empty or longer then [`u16::MAX`].
pub fn deterministic_blind_unchecked(
2021-12-23 21:03:38 +01:00
input: &[u8],
2022-01-21 22:52:09 +01:00
blind: <CS::Group as Group>::Scalar,
) -> Result<VerifiableClientBlindResult<CS>> {
let blinded_element = deterministic_blind_unchecked::<CS>(input, &blind, Mode::Verifiable)?;
Ok(VerifiableClientBlindResult {
state: Self {
blind,
blinded_element,
},
2022-01-21 22:52:09 +01:00
message: BlindedElement(blinded_element),
})
}
2021-12-23 01:17:03 +01:00
/// Computes the third step for the multiplicative blinding version of
/// DH-OPRF, in which the client unblinds the server's message.
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// - [`Error::Input`] if the `input` is empty or longer then [`u16::MAX`].
/// - [`Error::Metadata`] if the `metadata` is longer then `u16::MAX - 21`.
/// - [`Error::ProofVerification`] if the `proof` failed to verify.
pub fn finalize(
&self,
2021-12-23 21:03:38 +01:00
input: &[u8],
2022-01-21 22:52:09 +01:00
evaluation_element: &EvaluationElement<CS>,
proof: &Proof<CS>,
pk: <CS::Group as Group>::Elem,
metadata: Option<&[u8]>,
2022-01-21 22:52:09 +01:00
) -> Result<Output<CS::Hash>> {
2022-01-25 05:55:02 +01:00
let inputs = core::array::from_ref(&input);
let clients = core::array::from_ref(self);
let messages = core::array::from_ref(evaluation_element);
2021-12-21 20:17:02 +01:00
2021-12-23 21:03:38 +01:00
let mut batch_result =
Self::batch_finalize(inputs, clients, messages, proof, pk, metadata)?;
batch_result.next().unwrap()
}
2021-12-23 01:17:03 +01:00
/// Allows for batching of the finalization of multiple [VerifiableClient]
/// and [EvaluationElement] pairs
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// - [`Error::Metadata`] if the `metadata` is longer then `u16::MAX - 21`.
/// - [`Error::Batch`] if the number of `clients` and `messages` don't match
/// or is longer then [`u16::MAX`].
/// - [`Error::ProofVerification`] if the `proof` failed to verify.
///
/// The resulting messages can each fail individually with [`Error::Input`]
/// if the `input` is empty or longer then [`u16::MAX`].
2021-12-23 21:03:38 +01:00
pub fn batch_finalize<'a, I: 'a, II, IC, IM>(
inputs: &'a II,
clients: &'a IC,
messages: &'a IM,
2022-01-21 22:52:09 +01:00
proof: &Proof<CS>,
pk: <CS::Group as Group>::Elem,
2021-12-23 21:03:38 +01:00
metadata: Option<&'a [u8]>,
2022-01-21 22:52:09 +01:00
) -> Result<VerifiableClientBatchFinalizeResult<'a, CS, I, II, IC, IM>>
where
2022-01-21 22:52:09 +01:00
CS: 'a,
2021-12-23 21:03:38 +01:00
I: AsRef<[u8]>,
&'a II: 'a + IntoIterator<Item = I>,
<&'a II as IntoIterator>::IntoIter: ExactSizeIterator,
2022-01-21 22:52:09 +01:00
&'a IC: 'a + IntoIterator<Item = &'a VerifiableClient<CS>>,
<&'a IC as IntoIterator>::IntoIter: ExactSizeIterator,
2022-01-21 22:52:09 +01:00
&'a IM: 'a + IntoIterator<Item = &'a EvaluationElement<CS>>,
<&'a IM as IntoIterator>::IntoIter: ExactSizeIterator,
{
let metadata = metadata.unwrap_or_default();
2021-12-23 21:03:38 +01:00
let unblinded_elements = verifiable_unblind(clients, messages, pk, proof, metadata)?;
2021-12-23 21:03:38 +01:00
let inputs_and_unblinded_elements = inputs.into_iter().zip(unblinded_elements);
2022-01-25 05:55:02 +01:00
Ok(finalize_after_unblind::<CS, _, _>(
2021-12-23 21:03:38 +01:00
inputs_and_unblinded_elements,
metadata,
Mode::Verifiable,
2022-01-25 05:55:02 +01:00
))
}
#[cfg(test)]
/// Only used for test functions
2022-01-21 22:52:09 +01:00
pub fn from_blind_and_element(
blind: <CS::Group as Group>::Scalar,
blinded_element: <CS::Group as Group>::Elem,
) -> Self {
Self {
2021-10-06 00:19:20 +02:00
blind,
blinded_element,
}
}
#[cfg(test)]
/// Only used for test functions
2022-01-21 22:52:09 +01:00
pub fn get_blind(&self) -> <CS::Group as Group>::Scalar {
self.blind
}
}
2022-01-21 22:52:09 +01:00
impl<CS: CipherSuite> NonVerifiableServer<CS>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-09-15 17:49:31 -07:00
/// Produces a new instance of a [NonVerifiableServer] using a supplied RNG
2022-01-25 05:55:02 +01:00
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
2022-01-21 22:52:09 +01:00
let mut seed = Output::<CS::Hash>::default();
rng.fill_bytes(&mut seed);
2022-01-25 05:55:02 +01:00
// This can't fail as the hash output is type constrained.
Self::new_from_seed(&seed).unwrap()
}
2021-12-23 01:17:03 +01:00
/// Produces a new instance of a [NonVerifiableServer] using a supplied set
/// of bytes to represent the server's private key
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Deserialization`] if the private key is not a valid point on
/// the group or zero.
2021-12-25 22:54:27 +01:00
pub fn new_with_key(private_key_bytes: &[u8]) -> Result<Self> {
2022-01-28 01:38:17 +01:00
let sk = CS::Group::deserialize_scalar(private_key_bytes)?;
2022-01-21 22:52:09 +01:00
Ok(Self { sk })
}
2021-12-23 01:17:03 +01: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.
2021-09-15 17:49:31 -07:00
///
/// Corresponds to DeriveKeyPair() function from the VOPRF specification.
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Seed`] if the `seed` is empty or longer then [`u16::MAX`].
2021-12-25 22:54:27 +01:00
pub fn new_from_seed(seed: &[u8]) -> Result<Self> {
2022-01-25 05:55:02 +01:00
let sk = CS::Group::hash_to_scalar::<CS>(&[seed], Mode::Base).map_err(|_| Error::Seed)?;
2022-01-21 22:52:09 +01:00
Ok(Self { sk })
}
// Only used for tests
#[cfg(test)]
2022-01-21 22:52:09 +01:00
pub fn get_private_key(&self) -> <CS::Group as Group>::Scalar {
self.sk
}
2021-12-23 01:17:03 +01: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.
2022-01-25 05:55:02 +01:00
///
/// # Errors
2022-01-28 01:38:17 +01:00
/// - [`Error::Metadata`] if the `metadata` is longer then `u16::MAX - 21`.
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
pub fn evaluate(
&self,
2022-01-21 22:52:09 +01:00
blinded_element: &BlindedElement<CS>,
metadata: Option<&[u8]>,
2022-01-28 01:38:17 +01:00
) -> Result<EvaluationElement<CS>> {
2022-01-18 12:34:28 +01:00
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.1.1-1
2022-01-21 22:52:09 +01:00
let context_string = get_context_string::<CS>(Mode::Base);
2022-01-18 12:34:28 +01:00
let metadata = metadata.unwrap_or_default();
// context = "Context-" || contextString || I2OSP(len(info), 2) || info
let context = GenericArray::from(STR_CONTEXT)
.concat(context_string)
2022-01-25 05:55:02 +01:00
.concat(i2osp_2(metadata.len()).map_err(|_| Error::Metadata)?);
2022-01-18 12:34:28 +01:00
let context = [&context, metadata];
// m = GG.HashToScalar(context)
2022-01-25 05:55:02 +01:00
let m =
CS::Group::hash_to_scalar::<CS>(&context, Mode::Base).map_err(|_| Error::Metadata)?;
2022-01-18 12:34:28 +01:00
// t = skS + m
let t = self.sk + &m;
2022-01-28 01:38:17 +01:00
// if t == 0:
if bool::from(CS::Group::is_zero_scalar(t)) {
// raise InverseError
return Err(Error::Protocol);
}
2022-01-18 12:34:28 +01:00
// Z = t^(-1) * R
2022-01-21 22:52:09 +01:00
let z = blinded_element.0 * &CS::Group::invert_scalar(t);
2022-01-18 12:34:28 +01:00
2022-01-28 01:38:17 +01:00
Ok(EvaluationElement(z))
}
}
2022-01-21 22:52:09 +01:00
impl<CS: CipherSuite> VerifiableServer<CS>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-09-15 17:49:31 -07:00
/// Produces a new instance of a [VerifiableServer] using a supplied RNG
2022-01-25 05:55:02 +01:00
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
2022-01-21 22:52:09 +01:00
let mut seed = Output::<CS::Hash>::default();
rng.fill_bytes(&mut seed);
2022-01-25 05:55:02 +01:00
// This can't fail as the hash output is type constrained.
Self::new_from_seed(&seed).unwrap()
2021-09-09 01:56:54 -07:00
}
2021-12-23 01:17:03 +01:00
/// Produces a new instance of a [VerifiableServer] using a supplied set of
/// bytes to represent the server's private key
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Deserialization`] if the private key is not a valid point on
/// the group or zero.
2021-12-25 22:54:27 +01:00
pub fn new_with_key(key: &[u8]) -> Result<Self> {
2022-01-28 01:38:17 +01:00
let sk = CS::Group::deserialize_scalar(key)?;
2022-01-21 22:52:09 +01:00
let pk = CS::Group::base_elem() * &sk;
Ok(Self { sk, pk })
}
2021-12-23 01:17:03 +01: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.
2021-09-15 17:49:31 -07:00
///
/// Corresponds to DeriveKeyPair() function from the VOPRF specification.
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Seed`] if the `seed` is empty or longer then [`u16::MAX`].
2021-12-25 22:54:27 +01:00
pub fn new_from_seed(seed: &[u8]) -> Result<Self> {
2022-01-25 05:55:02 +01:00
let sk =
CS::Group::hash_to_scalar::<CS>(&[seed], Mode::Verifiable).map_err(|_| Error::Seed)?;
2022-01-21 22:52:09 +01:00
let pk = CS::Group::base_elem() * &sk;
Ok(Self { sk, pk })
2021-09-09 01:56:54 -07:00
}
// Only used for tests
#[cfg(test)]
2022-01-21 22:52:09 +01:00
pub fn get_private_key(&self) -> <CS::Group as Group>::Scalar {
self.sk
}
2021-12-23 01:17:03 +01: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.
2022-01-25 05:55:02 +01:00
///
/// # Errors
2022-01-28 01:38:17 +01:00
/// - [`Error::Metadata`] if the `metadata` is longer then `u16::MAX - 21`.
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
pub fn evaluate<R: RngCore + CryptoRng>(
&self,
rng: &mut R,
2022-01-21 22:52:09 +01:00
blinded_element: &BlindedElement<CS>,
metadata: Option<&[u8]>,
2022-01-21 22:52:09 +01:00
) -> Result<VerifiableServerEvaluateResult<CS>> {
2021-12-29 09:14:28 +01:00
let VerifiableServerBatchEvaluatePrepareResult {
prepared_evaluation_elements: mut evaluation_elements,
t,
2022-01-25 05:55:02 +01:00
} = self.batch_evaluate_prepare(iter::once(blinded_element), metadata)?;
2021-12-23 21:03:38 +01:00
2021-12-29 09:14:28 +01:00
let prepared_element = [evaluation_elements.next().unwrap()];
2021-12-23 21:03:38 +01:00
2022-01-25 05:55:02 +01:00
// This can't fail because we know the size of the inputs.
2021-12-29 09:14:28 +01:00
let VerifiableServerBatchEvaluateFinishResult {
mut messages,
proof,
2022-01-25 05:55:02 +01:00
} = Self::batch_evaluate_finish(rng, iter::once(blinded_element), &prepared_element, &t)
.unwrap();
2021-12-21 20:17:02 +01:00
2021-12-29 09:14:28 +01:00
let message = messages.next().unwrap();
2021-12-23 21:03:38 +01:00
//let batch_result = self.batch_evaluate(rng, blinded_elements, metadata)?;
2021-12-29 09:14:28 +01:00
Ok(VerifiableServerEvaluateResult { message, proof })
}
2021-12-23 01:17:03 +01:00
/// Allows for batching of the evaluation of multiple [BlindedElement]
/// messages from a [VerifiableClient]
2022-01-25 05:55:02 +01:00
///
/// # Errors
2022-01-28 01:38:17 +01:00
/// - [`Error::Metadata`] if the `metadata` is longer then `u16::MAX - 21`.
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
2021-12-23 21:03:38 +01:00
#[cfg(feature = "alloc")]
pub fn batch_evaluate<'a, R: RngCore + CryptoRng, I>(
&self,
rng: &mut R,
blinded_elements: &'a I,
metadata: Option<&[u8]>,
2022-01-21 22:52:09 +01:00
) -> Result<VerifiableServerBatchEvaluateResult<CS>>
where
2022-01-21 22:52:09 +01:00
CS: 'a,
&'a I: IntoIterator<Item = &'a BlindedElement<CS>>,
<&'a I as IntoIterator>::IntoIter: ExactSizeIterator,
2021-12-23 21:03:38 +01:00
{
2021-12-29 09:14:28 +01:00
let VerifiableServerBatchEvaluatePrepareResult {
prepared_evaluation_elements: evaluation_elements,
t,
} = self.batch_evaluate_prepare(blinded_elements.into_iter(), metadata)?;
2021-12-23 21:03:38 +01:00
2021-12-29 09:14:28 +01:00
let prepared_elements = evaluation_elements.collect();
2021-12-23 21:03:38 +01:00
2022-01-25 05:55:02 +01:00
// This can't fail because we know the size of the inputs.
2021-12-29 09:14:28 +01:00
let VerifiableServerBatchEvaluateFinishResult { messages, proof } =
Self::batch_evaluate_finish::<_, _, Vec<_>>(
rng,
blinded_elements.into_iter(),
&prepared_elements,
&t,
2022-01-25 05:55:02 +01:00
)
.unwrap();
2021-12-23 21:03:38 +01:00
Ok(VerifiableServerBatchEvaluateResult {
2021-12-29 09:14:28 +01:00
messages: messages.collect(),
2021-12-23 21:03:38 +01:00
proof,
})
}
2021-12-29 09:14:28 +01:00
/// Alternative version of [`batch_evaluate`](Self::batch_evaluate) without
/// memory allocation. Returned [`PreparedEvaluationElement`] have to be
/// [`collect`](Iterator::collect)ed and passed into
/// [`batch_evaluate_finish`](Self::batch_evaluate_finish).
2022-01-25 05:55:02 +01:00
///
/// # Errors
2022-01-28 01:38:17 +01:00
/// - [`Error::Metadata`] if the `metadata` is longer then `u16::MAX - 21`.
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
2022-01-21 22:52:09 +01:00
pub fn batch_evaluate_prepare<'a, I: Iterator<Item = &'a BlindedElement<CS>>>(
2021-12-23 21:03:38 +01:00
&self,
blinded_elements: I,
metadata: Option<&[u8]>,
2022-01-21 22:52:09 +01:00
) -> Result<VerifiableServerBatchEvaluatePrepareResult<'a, CS, I>> {
2022-01-18 12:34:28 +01:00
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.2.1-1
2022-01-21 22:52:09 +01:00
let context_string = get_context_string::<CS>(Mode::Verifiable);
2022-01-18 12:34:28 +01:00
let metadata = metadata.unwrap_or_default();
// context = "Context-" || contextString || I2OSP(len(info), 2) || info
let context = GenericArray::from(STR_CONTEXT)
.concat(context_string)
2022-01-25 05:55:02 +01:00
.concat(i2osp_2(metadata.len()).map_err(|_| Error::Metadata)?);
2022-01-18 12:34:28 +01:00
let context = [&context, metadata];
2022-01-25 05:55:02 +01:00
let m = CS::Group::hash_to_scalar::<CS>(&context, Mode::Verifiable)
.map_err(|_| Error::Metadata)?;
let t = self.sk + &m;
2022-01-28 01:38:17 +01:00
// if t == 0:
if bool::from(CS::Group::is_zero_scalar(t)) {
// raise InverseError
return Err(Error::Protocol);
}
2021-12-29 09:14:28 +01:00
let evaluation_elements = blinded_elements
// To make a return type possible, we have to convert to a `fn` pointer, which isn't
// possible if we `move` from context.
2022-01-21 22:52:09 +01:00
.zip(iter::repeat(CS::Group::invert_scalar(t)))
.map(<fn((&BlindedElement<CS>, _)) -> _>::from(|(x, t)| {
PreparedEvaluationElement(EvaluationElement(x.0 * &t))
2021-12-29 09:14:28 +01:00
}));
2021-12-29 09:14:28 +01:00
Ok(VerifiableServerBatchEvaluatePrepareResult {
prepared_evaluation_elements: evaluation_elements,
2022-01-21 22:52:09 +01:00
t: PreparedTscalar(t),
2021-12-29 09:14:28 +01:00
})
2021-12-23 21:03:38 +01:00
}
2021-12-29 09:14:28 +01:00
/// See [`batch_evaluate_prepare`](Self::batch_evaluate_prepare) for more
/// details.
2022-01-25 05:55:02 +01:00
///
/// # Errors
/// [`Error::Batch`] if the number of `blinded_elements` and
/// `evaluation_elements` don't match or is longer then [`u16::MAX`].
2021-12-29 09:14:28 +01:00
pub fn batch_evaluate_finish<'a, 'b, R: RngCore + CryptoRng, IB, IE>(
2021-12-23 21:03:38 +01:00
rng: &mut R,
blinded_elements: IB,
2021-12-29 09:14:28 +01:00
evaluation_elements: &'b IE,
2022-01-21 22:52:09 +01:00
PreparedTscalar(t): &PreparedTscalar<CS>,
) -> Result<VerifiableServerBatchEvaluateFinishResult<'b, CS, IE>>
2021-12-23 21:03:38 +01:00
where
2022-01-21 22:52:09 +01:00
CS: 'a + 'b,
IB: Iterator<Item = &'a BlindedElement<CS>> + ExactSizeIterator,
&'b IE: IntoIterator<Item = &'b PreparedEvaluationElement<CS>>,
2021-12-29 09:14:28 +01:00
<&'b IE as IntoIterator>::IntoIter: ExactSizeIterator,
2021-12-23 21:03:38 +01:00
{
2022-01-21 22:52:09 +01:00
let g = CS::Group::base_elem();
2021-12-29 09:14:28 +01:00
let u = g * t;
2021-12-29 09:14:28 +01:00
let proof = generate_proof(
rng,
*t,
g,
u,
evaluation_elements
.into_iter()
2022-01-28 01:38:17 +01:00
.map(|element| element.0.clone()),
blinded_elements.cloned(),
2021-12-29 09:14:28 +01:00
)?;
let messages =
evaluation_elements
.into_iter()
2022-01-21 22:52:09 +01:00
.map(<fn(&PreparedEvaluationElement<CS>) -> _>::from(|element| {
2022-01-28 01:38:17 +01:00
element.0.clone()
2022-01-21 22:52:09 +01:00
}));
2021-12-29 09:14:28 +01:00
Ok(VerifiableServerBatchEvaluateFinishResult { messages, proof })
}
2021-09-15 17:49:31 -07:00
/// Retrieves the server's public key
2022-01-21 22:52:09 +01:00
pub fn get_public_key(&self) -> <CS::Group as Group>::Elem {
self.pk
}
}
2022-01-28 01:38:17 +01:00
impl<CS: CipherSuite> BlindedElement<CS>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
#[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: <CS::Group as Group>::Elem) -> Self {
Self(value)
}
#[cfg(feature = "danger")]
/// Exposes the internal value
pub fn value(&self) -> <CS::Group as Group>::Elem {
self.0
}
}
impl<CS: CipherSuite> EvaluationElement<CS>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
#[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: <CS::Group as Group>::Elem) -> Self {
Self(value)
}
#[cfg(feature = "danger")]
/// Exposes the internal value
pub fn value(&self) -> <CS::Group as Group>::Elem {
self.0
}
}
2021-09-20 00:17:53 -07:00
/////////////////////////
// Convenience Structs //
//==================== //
/////////////////////////
/// Contains the fields that are returned by a non-verifiable client blind
2022-01-28 01:38:17 +01:00
#[derive(DeriveWhere)]
#[derive_where(Debug; <CS::Group as Group>::Scalar, <CS::Group as Group>::Elem)]
2022-01-21 22:52:09 +01:00
pub struct NonVerifiableClientBlindResult<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-09-20 00:17:53 -07:00
/// The state to be persisted on the client
2022-01-21 22:52:09 +01:00
pub state: NonVerifiableClient<CS>,
2021-09-20 00:17:53 -07:00
/// The message to send to the server
2022-01-21 22:52:09 +01:00
pub message: BlindedElement<CS>,
2021-09-20 00:17:53 -07:00
}
/// Contains the fields that are returned by a verifiable client blind
2022-01-28 01:38:17 +01:00
#[derive(DeriveWhere)]
#[derive_where(Debug; <CS::Group as Group>::Scalar, <CS::Group as Group>::Elem)]
2022-01-21 22:52:09 +01:00
pub struct VerifiableClientBlindResult<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-09-20 00:17:53 -07:00
/// The state to be persisted on the client
2022-01-21 22:52:09 +01:00
pub state: VerifiableClient<CS>,
2021-09-20 00:17:53 -07:00
/// The message to send to the server
2022-01-21 22:52:09 +01:00
pub message: BlindedElement<CS>,
2021-09-20 00:17:53 -07:00
}
2021-12-25 22:54:27 +01:00
/// Concrete return type for [`VerifiableClient::batch_finalize`].
2022-01-21 22:52:09 +01:00
pub type VerifiableClientBatchFinalizeResult<'a, C, I, II, IC, IM> = FinalizeAfterUnblindResult<
2021-12-23 21:03:38 +01:00
'a,
2022-01-21 22:52:09 +01:00
C,
2021-12-23 21:03:38 +01:00
I,
2022-01-21 22:52:09 +01:00
Zip<<&'a II as IntoIterator>::IntoIter, VerifiableUnblindResult<'a, C, IC, IM>>,
2021-12-23 21:03:38 +01:00
>;
2021-09-20 00:17:53 -07:00
/// Contains the fields that are returned by a verifiable server evaluate
2022-01-28 01:38:17 +01:00
#[derive(DeriveWhere)]
#[derive_where(Debug; <CS::Group as Group>::Scalar, <CS::Group as Group>::Elem)]
2022-01-21 22:52:09 +01:00
pub struct VerifiableServerEvaluateResult<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-09-20 00:17:53 -07:00
/// The message to send to the client
2022-01-21 22:52:09 +01:00
pub message: EvaluationElement<CS>,
2021-09-20 00:17:53 -07:00
/// The proof for the client to verify
2022-01-21 22:52:09 +01:00
pub proof: Proof<CS>,
2021-09-20 00:17:53 -07:00
}
2021-12-29 09:14:28 +01:00
/// Contains prepared [`EvaluationElement`]s by a verifiable server batch
/// evaluate preparation.
2022-01-28 01:38:17 +01:00
#[derive(DeriveWhere)]
#[derive_where(Clone, Zeroize(drop))]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Elem)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(crate = "serde", bound = "")
)]
2022-01-21 22:52:09 +01:00
pub struct PreparedEvaluationElement<CS: CipherSuite>(EvaluationElement<CS>)
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>;
2021-12-29 09:14:28 +01:00
/// Contains the prepared `t` by a verifiable server batch evaluate preparation.
#[derive(DeriveWhere)]
2022-01-28 01:38:17 +01:00
#[derive_where(Clone, Zeroize(drop))]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::Group as Group>::Scalar)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(crate = "serde", bound = "")
)]
pub struct PreparedTscalar<CS: CipherSuite>(
#[cfg_attr(feature = "serde", serde(with = "Scalar::<CS::Group>"))]
<CS::Group as Group>::Scalar,
)
2022-01-21 22:52:09 +01:00
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>;
2021-12-29 09:14:28 +01:00
2022-01-28 01:38:17 +01:00
/// Concrete type of [`EvaluationElement`]s in
/// [`VerifiableServerBatchEvaluatePrepareResult`].
pub type VerifiableServerBatchEvaluatePreparedEvaluationElements<CS, I> = Map<
Zip<I, Repeat<<<CS as CipherSuite>::Group as Group>::Scalar>>,
fn(
(
&BlindedElement<CS>,
<<CS as CipherSuite>::Group as Group>::Scalar,
),
) -> PreparedEvaluationElement<CS>,
>;
2021-12-29 09:14:28 +01:00
/// Contains the fields that are returned by a verifiable server batch evaluate
/// preparation.
2022-01-28 01:38:17 +01:00
#[derive(DeriveWhere)]
#[derive_where(Debug; I, <CS::Group as Group>::Scalar)]
2021-12-29 09:14:28 +01:00
pub struct VerifiableServerBatchEvaluatePrepareResult<
'a,
2022-01-21 22:52:09 +01:00
CS: 'a + CipherSuite,
I: Iterator<Item = &'a BlindedElement<CS>>,
> where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-12-29 09:14:28 +01:00
/// Prepared [`EvaluationElement`]s that will become messages.
2022-01-28 01:38:17 +01:00
pub prepared_evaluation_elements:
VerifiableServerBatchEvaluatePreparedEvaluationElements<CS, I>,
2021-12-29 09:14:28 +01:00
/// Prepared `t` needed to finish the verifiable server batch evaluation.
2022-01-21 22:52:09 +01:00
pub t: PreparedTscalar<CS>,
2021-12-29 09:14:28 +01:00
}
2022-01-28 01:38:17 +01:00
/// Concrete type of [`EvaluationElement`]s in
/// [`VerifiableServerBatchEvaluateFinishResult`].
pub type VerifiableServerBatchEvaluateFinishedMessages<'a, CS, I> = Map<
<&'a I as IntoIterator>::IntoIter,
fn(&PreparedEvaluationElement<CS>) -> EvaluationElement<CS>,
>;
2021-12-29 09:14:28 +01:00
/// Contains the fields that are returned by a verifiable server batch evaluate
/// finish.
2022-01-28 01:38:17 +01:00
#[derive(DeriveWhere)]
#[derive_where(Debug; <&'a I as core::iter::IntoIterator>::IntoIter, <CS::Group as Group>::Scalar)]
2022-01-21 22:52:09 +01:00
pub struct VerifiableServerBatchEvaluateFinishResult<'a, CS: 'a + CipherSuite, I>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
&'a I: IntoIterator<Item = &'a PreparedEvaluationElement<CS>>,
2021-12-29 09:14:28 +01:00
{
2022-01-28 01:38:17 +01:00
/// The [`EvaluationElement`]s to send to the client
pub messages: VerifiableServerBatchEvaluateFinishedMessages<'a, CS, I>,
2021-12-29 09:14:28 +01:00
/// The proof for the client to verify
2022-01-21 22:52:09 +01:00
pub proof: Proof<CS>,
2021-12-29 09:14:28 +01:00
}
2021-09-20 00:17:53 -07:00
/// Contains the fields that are returned by a verifiable server batch evaluate
2022-01-28 01:38:17 +01:00
#[derive(DeriveWhere)]
#[derive_where(Debug; <CS::Group as Group>::Scalar, <CS::Group as Group>::Elem)]
2021-12-23 21:03:38 +01:00
#[cfg(feature = "alloc")]
2022-01-21 22:52:09 +01:00
pub struct VerifiableServerBatchEvaluateResult<CS: CipherSuite>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-09-20 00:17:53 -07:00
/// The messages to send to the client
2022-01-21 22:52:09 +01:00
pub messages: alloc::vec::Vec<EvaluationElement<CS>>,
2021-09-20 00:17:53 -07:00
/// The proof for the client to verify
2022-01-21 22:52:09 +01:00
pub proof: Proof<CS>,
2021-09-20 00:17:53 -07:00
}
2022-01-28 01:38:17 +01:00
/////////////////////
// Inner functions //
// =============== //
/////////////////////
2021-10-11 02:51:12 +02:00
2022-01-21 22:52:09 +01:00
type BlindResult<C> = (
<<C as CipherSuite>::Group as Group>::Scalar,
<<C as CipherSuite>::Group as Group>::Elem,
);
// Inner function for blind. Returns the blind scalar and the blinded element
2022-01-25 05:55:02 +01:00
//
// Can only fail with [`Error::Input`].
2022-01-21 22:52:09 +01:00
fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
input: &[u8],
blinding_factor_rng: &mut R,
mode: Mode,
2022-01-21 22:52:09 +01:00
) -> Result<BlindResult<CS>>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
// Choose a random scalar that must be non-zero
2022-01-21 22:52:09 +01:00
let blind = CS::Group::random_scalar(blinding_factor_rng);
let blinded_element = deterministic_blind_unchecked::<CS>(input, &blind, mode)?;
Ok((blind, blinded_element))
}
2021-12-23 01:17:03 +01:00
// 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.
2022-01-25 05:55:02 +01:00
//
// Can only fail with [`Error::Input`].
2022-01-21 22:52:09 +01:00
fn deterministic_blind_unchecked<CS: CipherSuite>(
input: &[u8],
2022-01-21 22:52:09 +01:00
blind: &<CS::Group as Group>::Scalar,
mode: Mode,
2022-01-21 22:52:09 +01:00
) -> Result<<CS::Group as Group>::Elem>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-25 05:55:02 +01:00
let hashed_point = CS::Group::hash_to_curve::<CS>(&[input], mode).map_err(|_| Error::Input)?;
Ok(hashed_point * blind)
}
2022-01-21 22:52:09 +01:00
type VerifiableUnblindResult<'a, CS, IC, IM> = Map<
2021-12-23 21:03:38 +01:00
Zip<
2022-01-04 00:45:05 +01:00
Map<
<&'a IC as IntoIterator>::IntoIter,
2022-01-21 22:52:09 +01:00
fn(&VerifiableClient<CS>) -> <<CS as CipherSuite>::Group as Group>::Scalar,
2022-01-04 00:45:05 +01:00
>,
2021-12-23 21:03:38 +01:00
<&'a IM as IntoIterator>::IntoIter,
>,
2022-01-21 22:52:09 +01:00
fn(
(
<<CS as CipherSuite>::Group as Group>::Scalar,
&EvaluationElement<CS>,
),
) -> <<CS as CipherSuite>::Group as Group>::Elem,
2021-12-23 21:03:38 +01:00
>;
2022-01-25 05:55:02 +01:00
// Can only fail with [`Error::Metadata`], [`Error::Batch] or
// [`Error::ProofVerification`].
2022-01-21 22:52:09 +01:00
fn verifiable_unblind<'a, CS: 'a + CipherSuite, IC, IM>(
2021-12-23 21:03:38 +01:00
clients: &'a IC,
messages: &'a IM,
2022-01-21 22:52:09 +01:00
pk: <CS::Group as Group>::Elem,
proof: &Proof<CS>,
2021-09-15 17:49:31 -07:00
info: &[u8],
2022-01-21 22:52:09 +01:00
) -> Result<VerifiableUnblindResult<'a, CS, IC, IM>>
where
2022-01-21 22:52:09 +01:00
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
&'a IC: 'a + IntoIterator<Item = &'a VerifiableClient<CS>>,
2021-12-23 21:03:38 +01:00
<&'a IC as IntoIterator>::IntoIter: ExactSizeIterator,
2022-01-21 22:52:09 +01:00
&'a IM: 'a + IntoIterator<Item = &'a EvaluationElement<CS>>,
2021-12-23 21:03:38 +01:00
<&'a IM as IntoIterator>::IntoIter: ExactSizeIterator,
{
2022-01-18 12:34:28 +01:00
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.4.2-2
2022-01-21 22:52:09 +01:00
let context_string = get_context_string::<CS>(Mode::Verifiable);
2022-01-18 12:34:28 +01:00
// context = "Context-" || contextString || I2OSP(len(info), 2) || info
let context = GenericArray::from(STR_CONTEXT)
.concat(context_string)
2022-01-25 05:55:02 +01:00
.concat(i2osp_2(info.len()).map_err(|_| Error::Metadata)?);
2022-01-18 12:34:28 +01:00
let context = [&context, info];
2021-09-15 17:49:31 -07:00
2022-01-25 05:55:02 +01:00
// The `input` used here is the metadata.
let m =
CS::Group::hash_to_scalar::<CS>(&context, Mode::Verifiable).map_err(|_| Error::Metadata)?;
2021-09-15 17:49:31 -07:00
2022-01-21 22:52:09 +01:00
let g = CS::Group::base_elem();
2021-09-15 17:49:31 -07:00
let t = g * &m;
let u = t + &pk;
2021-12-23 21:03:38 +01:00
let blinds = clients
.into_iter()
// Convert to `fn` pointer to make a return type possible.
2022-01-21 22:52:09 +01:00
.map(<fn(&VerifiableClient<CS>) -> _>::from(|x| x.blind));
2022-01-28 01:38:17 +01:00
let evaluation_elements = messages.into_iter().cloned();
2022-01-21 22:52:09 +01:00
let blinded_elements = clients
.into_iter()
.map(|client| BlindedElement(client.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
2021-12-23 21:03:38 +01:00
Ok(blinds
.zip(messages.into_iter())
2022-01-21 22:52:09 +01:00
.map(|(blind, x)| x.0 * &CS::Group::invert_scalar(blind)))
2021-09-15 17:49:31 -07:00
}
2022-01-25 05:55:02 +01:00
// Can only fail with [`Error::Batch`].
#[allow(clippy::many_single_char_names)]
2022-01-21 22:52:09 +01:00
fn generate_proof<CS: CipherSuite, R: RngCore + CryptoRng>(
rng: &mut R,
2022-01-21 22:52:09 +01:00
k: <CS::Group as Group>::Scalar,
a: <CS::Group as Group>::Elem,
b: <CS::Group as Group>::Elem,
cs: impl Iterator<Item = EvaluationElement<CS>> + ExactSizeIterator,
ds: impl Iterator<Item = BlindedElement<CS>> + ExactSizeIterator,
) -> Result<Proof<CS>>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-18 12:34:28 +01:00
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.2.2-1
let (m, z) = compute_composites(Some(k), b, cs, ds)?;
2021-10-06 00:53:18 +02:00
2022-01-21 22:52:09 +01:00
let r = CS::Group::random_scalar(rng);
let t2 = a * &r;
let t3 = m * &r;
2022-01-18 12:34:28 +01:00
// Bm = GG.SerializeElement(B)
2022-01-21 22:52:09 +01:00
let bm = CS::Group::serialize_elem(b);
2022-01-18 12:34:28 +01:00
// a0 = GG.SerializeElement(M)
2022-01-21 22:52:09 +01:00
let a0 = CS::Group::serialize_elem(m);
2022-01-18 12:34:28 +01:00
// a1 = GG.SerializeElement(Z)
2022-01-21 22:52:09 +01:00
let a1 = CS::Group::serialize_elem(z);
2022-01-18 12:34:28 +01:00
// a2 = GG.SerializeElement(t2)
2022-01-21 22:52:09 +01:00
let a2 = CS::Group::serialize_elem(t2);
2022-01-18 12:34:28 +01:00
// a3 = GG.SerializeElement(t3)
2022-01-21 22:52:09 +01:00
let a3 = CS::Group::serialize_elem(t3);
2022-01-18 12:34:28 +01:00
2022-01-21 22:52:09 +01:00
let elem_len = <CS::Group as Group>::ElemLen::U16.to_be_bytes();
2022-01-18 12:34:28 +01:00
// challengeDST = "Challenge-" || contextString
let challenge_dst =
2022-01-21 22:52:09 +01:00
GenericArray::from(STR_CHALLENGE).concat(get_context_string::<CS>(Mode::Verifiable));
2022-01-25 05:55:02 +01:00
let challenge_dst_len = i2osp_2_array(&challenge_dst);
2022-01-18 12:34:28 +01:00
// h2Input = I2OSP(len(Bm), 2) || Bm ||
// I2OSP(len(a0), 2) || a0 ||
// I2OSP(len(a1), 2) || a1 ||
// I2OSP(len(a2), 2) || a2 ||
// I2OSP(len(a3), 2) || a3 ||
// I2OSP(len(challengeDST), 2) || challengeDST
let h2_input = [
&elem_len,
bm.as_slice(),
&elem_len,
&a0,
&elem_len,
&a1,
&elem_len,
&a2,
&elem_len,
&a3,
&challenge_dst_len,
&challenge_dst,
];
2022-01-25 05:55:02 +01:00
// This can't fail, the size of the `input` is known.
let c_scalar = CS::Group::hash_to_scalar::<CS>(&h2_input, Mode::Verifiable).unwrap();
let s_scalar = r - &(c_scalar * &k);
2022-01-21 22:52:09 +01:00
Ok(Proof { c_scalar, s_scalar })
}
2022-01-25 05:55:02 +01:00
// Can only fail with [`Error::ProofVerification`] or [`Error::Batch`].
#[allow(clippy::many_single_char_names)]
2022-01-21 22:52:09 +01:00
fn verify_proof<CS: CipherSuite>(
a: <CS::Group as Group>::Elem,
b: <CS::Group as Group>::Elem,
cs: impl Iterator<Item = EvaluationElement<CS>> + ExactSizeIterator,
ds: impl Iterator<Item = BlindedElement<CS>> + ExactSizeIterator,
proof: &Proof<CS>,
) -> Result<()>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-18 12:34:28 +01:00
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.4.1-2
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);
2022-01-18 12:34:28 +01:00
// Bm = GG.SerializeElement(B)
2022-01-21 22:52:09 +01:00
let bm = CS::Group::serialize_elem(b);
2022-01-18 12:34:28 +01:00
// a0 = GG.SerializeElement(M)
2022-01-21 22:52:09 +01:00
let a0 = CS::Group::serialize_elem(m);
2022-01-18 12:34:28 +01:00
// a1 = GG.SerializeElement(Z)
2022-01-21 22:52:09 +01:00
let a1 = CS::Group::serialize_elem(z);
2022-01-18 12:34:28 +01:00
// a2 = GG.SerializeElement(t2)
2022-01-21 22:52:09 +01:00
let a2 = CS::Group::serialize_elem(t2);
2022-01-18 12:34:28 +01:00
// a3 = GG.SerializeElement(t3)
2022-01-21 22:52:09 +01:00
let a3 = CS::Group::serialize_elem(t3);
2022-01-18 12:34:28 +01:00
2022-01-21 22:52:09 +01:00
let elem_len = <CS::Group as Group>::ElemLen::U16.to_be_bytes();
2022-01-18 12:34:28 +01:00
// challengeDST = "Challenge-" || contextString
let challenge_dst =
2022-01-21 22:52:09 +01:00
GenericArray::from(STR_CHALLENGE).concat(get_context_string::<CS>(Mode::Verifiable));
2022-01-25 05:55:02 +01:00
let challenge_dst_len = i2osp_2_array(&challenge_dst);
2022-01-18 12:34:28 +01:00
// h2Input = I2OSP(len(Bm), 2) || Bm ||
// I2OSP(len(a0), 2) || a0 ||
// I2OSP(len(a1), 2) || a1 ||
// I2OSP(len(a2), 2) || a2 ||
// I2OSP(len(a3), 2) || a3 ||
// I2OSP(len(challengeDST), 2) || challengeDST
let h2_input = [
&elem_len,
bm.as_slice(),
&elem_len,
&a0,
&elem_len,
&a1,
&elem_len,
&a2,
&elem_len,
&a3,
&challenge_dst_len,
&challenge_dst,
];
2022-01-25 05:55:02 +01:00
// This can't fail, the size of the `input` is known.
let c = CS::Group::hash_to_scalar::<CS>(&h2_input, Mode::Verifiable).unwrap();
2021-10-14 20:09:00 +02:00
match c.ct_eq(&proof.c_scalar).into() {
true => Ok(()),
2022-01-25 05:55:02 +01:00
false => Err(Error::ProofVerification),
2021-09-09 01:56:54 -07:00
}
}
2022-01-21 22:52:09 +01:00
type FinalizeAfterUnblindResult<'a, C, I, IE> = Map<
2021-12-23 21:03:38 +01:00
Zip<IE, Repeat<(&'a [u8], GenericArray<u8, U20>)>>,
2022-01-21 22:52:09 +01:00
fn(
(
(I, <<C as CipherSuite>::Group as Group>::Elem),
(&'a [u8], GenericArray<u8, U20>),
),
) -> Result<Output<<C as CipherSuite>::Hash>>,
2021-12-23 21:03:38 +01:00
>;
2022-01-25 05:55:02 +01:00
// Returned values can only fail with [`Error::Input`] or [`Error::Metadata`].
fn finalize_after_unblind<
'a,
2022-01-21 22:52:09 +01:00
CS: CipherSuite,
2021-12-23 21:03:38 +01:00
I: AsRef<[u8]>,
2022-01-21 22:52:09 +01:00
IE: 'a + Iterator<Item = (I, <CS::Group as Group>::Elem)>,
>(
2021-12-23 21:03:38 +01:00
inputs_and_unblinded_elements: IE,
info: &'a [u8],
mode: Mode,
2022-01-25 05:55:02 +01:00
) -> FinalizeAfterUnblindResult<CS, I, IE>
2022-01-21 22:52:09 +01:00
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-18 12:34:28 +01:00
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.3.2-2
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.4.3-1
// finalizeDST = "Finalize-" || contextString
2022-01-21 22:52:09 +01:00
let finalize_dst = GenericArray::from(STR_FINALIZE).concat(get_context_string::<CS>(mode));
2022-01-25 05:55:02 +01:00
inputs_and_unblinded_elements
2021-12-23 21:03:38 +01:00
// To make a return type possible, we have to convert to a `fn` pointer,
// which isn't possible if we `move` from context.
.zip(iter::repeat((info, finalize_dst)))
.map(|((input, unblinded_element), (info, finalize_dst))| {
2022-01-25 05:55:02 +01:00
let finalize_dst_len = i2osp_2_array(&finalize_dst);
2022-01-21 22:52:09 +01:00
let elem_len = <CS::Group as Group>::ElemLen::U16.to_be_bytes();
2022-01-18 12:34:28 +01:00
// hashInput = I2OSP(len(input), 2) || input ||
// I2OSP(len(info), 2) || info ||
// I2OSP(len(unblindedElement), 2) || unblindedElement ||
// I2OSP(len(finalizeDST), 2) || finalizeDST
// return Hash(hashInput)
2022-01-21 22:52:09 +01:00
Ok(CS::Hash::new()
2022-01-25 05:55:02 +01:00
.chain_update(i2osp_2(input.as_ref().len()).map_err(|_| Error::Input)?)
2022-01-18 12:34:28 +01:00
.chain_update(input.as_ref())
2022-01-25 05:55:02 +01:00
.chain_update(i2osp_2(info.len()).map_err(|_| Error::Metadata)?)
2022-01-18 12:34:28 +01:00
.chain_update(info)
.chain_update(elem_len)
2022-01-21 22:52:09 +01:00
.chain_update(CS::Group::serialize_elem(unblinded_element))
2022-01-18 12:34:28 +01:00
.chain_update(finalize_dst_len)
.chain_update(finalize_dst)
2021-10-16 01:56:21 +02:00
.finalize())
2022-01-25 05:55:02 +01:00
})
}
2022-01-21 22:52:09 +01:00
type ComputeCompositesResult<C> = (
<<C as CipherSuite>::Group as Group>::Elem,
<<C as CipherSuite>::Group as Group>::Elem,
);
2022-01-25 05:55:02 +01:00
// Can only fail with [`Error::Batch`].
2022-01-21 22:52:09 +01:00
fn compute_composites<CS: CipherSuite>(
k_option: Option<<CS::Group as Group>::Scalar>,
b: <CS::Group as Group>::Elem,
c_slice: impl Iterator<Item = EvaluationElement<CS>> + ExactSizeIterator,
d_slice: impl Iterator<Item = BlindedElement<CS>> + ExactSizeIterator,
) -> Result<ComputeCompositesResult<CS>>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-18 12:34:28 +01:00
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.2.3-2
2022-01-21 22:52:09 +01:00
let elem_len = <CS::Group as Group>::ElemLen::U16.to_be_bytes();
2022-01-18 12:34:28 +01:00
if c_slice.len() != d_slice.len() {
2022-01-25 05:55:02 +01:00
return Err(Error::Batch);
}
2022-01-25 05:55:02 +01:00
let len = u16::try_from(c_slice.len()).map_err(|_| Error::Batch)?;
2022-01-18 12:34:28 +01:00
2022-01-21 22:52:09 +01:00
let seed_dst = GenericArray::from(STR_SEED).concat(get_context_string::<CS>(Mode::Verifiable));
let composite_dst =
2022-01-21 22:52:09 +01:00
GenericArray::from(STR_COMPOSITE).concat(get_context_string::<CS>(Mode::Verifiable));
2022-01-25 05:55:02 +01:00
let composite_dst_len = i2osp_2_array(&composite_dst);
2022-01-18 12:34:28 +01:00
2022-01-21 22:52:09 +01:00
let seed = CS::Hash::new()
2022-01-18 12:34:28 +01:00
.chain_update(&elem_len)
2022-01-21 22:52:09 +01:00
.chain_update(CS::Group::serialize_elem(b))
2022-01-25 05:55:02 +01:00
.chain_update(i2osp_2_array(&seed_dst))
2022-01-18 12:34:28 +01:00
.chain_update(seed_dst)
2021-10-16 01:56:21 +02:00
.finalize();
2022-01-25 05:55:02 +01:00
let seed_len = i2osp_2_array(&seed);
2022-01-18 12:34:28 +01:00
2022-01-21 22:52:09 +01:00
let mut m = CS::Group::identity_elem();
let mut z = CS::Group::identity_elem();
2022-01-18 12:34:28 +01:00
for (i, (c, d)) in (0..len).zip(c_slice.zip(d_slice)) {
// Ci = GG.SerializeElement(Cs[i])
2022-01-21 22:52:09 +01:00
let ci = CS::Group::serialize_elem(c.0);
2022-01-18 12:34:28 +01:00
// Di = GG.SerializeElement(Ds[i])
2022-01-21 22:52:09 +01:00
let di = CS::Group::serialize_elem(d.0);
2022-01-18 12:34:28 +01:00
// h2Input = I2OSP(len(seed), 2) || seed || I2OSP(i, 2) ||
// I2OSP(len(Ci), 2) || Ci ||
// I2OSP(len(Di), 2) || Di ||
// I2OSP(len(compositeDST), 2) || compositeDST
let h2_input = [
2022-01-25 05:55:02 +01:00
seed_len.as_slice(),
&seed,
2022-01-18 12:34:28 +01:00
&i.to_be_bytes(),
&elem_len,
&ci,
&elem_len,
&di,
&composite_dst_len,
&composite_dst,
];
2022-01-25 05:55:02 +01:00
// This can't fail, the size of the `input` is known.
let di = CS::Group::hash_to_scalar::<CS>(&h2_input, Mode::Verifiable).unwrap();
2022-01-21 22:52:09 +01:00
m = c.0 * &di + &m;
z = match k_option {
Some(_) => z,
2022-01-21 22:52:09 +01:00
None => d.0 * &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>
2022-01-21 22:52:09 +01:00
pub(crate) fn get_context_string<CS: CipherSuite>(mode: Mode) -> GenericArray<u8, U11>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2022-01-18 12:34:28 +01:00
GenericArray::from(STR_VOPRF)
.concat([mode.to_u8()].into())
2022-01-21 22:52:09 +01:00
.concat(CS::ID.to_be_bytes().into())
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 {
2021-12-23 21:03:38 +01:00
use core::ops::Add;
2021-12-23 01:17:03 +01:00
2021-12-29 09:14:28 +01:00
use ::alloc::vec;
use ::alloc::vec::Vec;
2021-12-23 21:03:38 +01:00
use generic_array::typenum::Sum;
2022-01-18 12:34:28 +01:00
use generic_array::ArrayLength;
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-12-23 01:17:03 +01:00
use super::*;
2021-12-25 22:54:27 +01:00
use crate::Group;
2021-12-23 01:17:03 +01:00
2022-01-21 22:52:09 +01:00
fn prf<CS: CipherSuite>(
input: &[u8],
2022-01-21 22:52:09 +01:00
key: <CS::Group as Group>::Scalar,
info: &[u8],
mode: Mode,
2022-01-21 22:52:09 +01:00
) -> Output<CS::Hash>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let point = CS::Group::hash_to_curve::<CS>(&[input], mode).unwrap();
2022-01-18 12:34:28 +01:00
2022-01-21 22:52:09 +01:00
let context_string = get_context_string::<CS>(mode);
2022-01-18 12:34:28 +01:00
let info_len = i2osp_2(info.len()).unwrap();
let context = [&STR_CONTEXT, context_string.as_slice(), &info_len, info];
2021-10-16 01:56:21 +02:00
2022-01-21 22:52:09 +01:00
let m = CS::Group::hash_to_scalar::<CS>(&context, mode).unwrap();
2022-01-21 22:52:09 +01:00
let res = point * &CS::Group::invert_scalar(key + &m);
2022-01-25 05:55:02 +01:00
finalize_after_unblind::<CS, _, _>(iter::once((input, res)), info, mode)
2021-12-23 21:03:38 +01:00
.next()
.unwrap()
.unwrap()
2021-09-09 01:56:54 -07:00
}
2022-01-21 22:52:09 +01:00
fn base_retrieval<CS: CipherSuite>()
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let input = b"input";
let info = b"info";
2021-09-09 01:56:54 -07:00
let mut rng = OsRng;
2022-01-21 22:52:09 +01:00
let client_blind_result = NonVerifiableClient::<CS>::blind(input, &mut rng).unwrap();
2022-01-25 05:55:02 +01:00
let server = NonVerifiableServer::<CS>::new(&mut rng);
2022-01-28 01:38:17 +01:00
let message = server
2021-12-21 20:17:02 +01:00
.evaluate(&client_blind_result.message, Some(info))
2021-09-20 00:17:53 -07:00
.unwrap();
let client_finalize_result = client_blind_result
.state
2022-01-28 01:38:17 +01:00
.finalize(input, &message, Some(info))
2021-09-20 00:17:53 -07:00
.unwrap();
2022-01-21 22:52:09 +01:00
let res2 = prf::<CS>(input, server.get_private_key(), info, Mode::Base);
2021-10-06 00:53:18 +02:00
assert_eq!(client_finalize_result, res2);
}
2022-01-21 22:52:09 +01:00
fn verifiable_retrieval<CS: CipherSuite>()
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let input = b"input";
let info = b"info";
let mut rng = OsRng;
2022-01-21 22:52:09 +01:00
let client_blind_result = VerifiableClient::<CS>::blind(input, &mut rng).unwrap();
2022-01-25 05:55:02 +01:00
let server = VerifiableServer::<CS>::new(&mut rng);
let server_result = server
2021-12-21 20:17:02 +01:00
.evaluate(&mut rng, &client_blind_result.message, Some(info))
.unwrap();
let client_finalize_result = client_blind_result
.state
.finalize(
2021-12-23 21:03:38 +01:00
input,
2021-12-21 20:17:02 +01:00
&server_result.message,
&server_result.proof,
server.get_public_key(),
Some(info),
)
.unwrap();
2022-01-21 22:52:09 +01:00
let res2 = prf::<CS>(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
}
2022-01-21 22:52:09 +01:00
fn verifiable_bad_public_key<CS: CipherSuite>()
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let input = b"input";
let info = b"info";
let mut rng = OsRng;
2022-01-21 22:52:09 +01:00
let client_blind_result = VerifiableClient::<CS>::blind(input, &mut rng).unwrap();
2022-01-25 05:55:02 +01:00
let server = VerifiableServer::<CS>::new(&mut rng);
let server_result = server
2021-12-21 20:17:02 +01:00
.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
2022-01-21 22:52:09 +01:00
CS::Group::hash_to_curve::<CS>(&[b"msg"], Mode::Base).unwrap()
};
let client_finalize_result = client_blind_result.state.finalize(
2021-12-23 21:03:38 +01:00
input,
2021-12-21 20:17:02 +01:00
&server_result.message,
&server_result.proof,
wrong_pk,
Some(info),
);
assert!(client_finalize_result.is_err());
}
2022-01-21 22:52:09 +01:00
fn verifiable_batch_retrieval<CS: CipherSuite>()
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
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 {
2021-12-23 21:03:38 +01:00
let mut input = [0u8; 32];
rng.fill_bytes(&mut input);
2022-01-21 22:52:09 +01:00
let client_blind_result = VerifiableClient::<CS>::blind(&input, &mut rng).unwrap();
inputs.push(input);
client_states.push(client_blind_result.state);
client_messages.push(client_blind_result.message);
}
2022-01-25 05:55:02 +01:00
let server = VerifiableServer::<CS>::new(&mut rng);
2021-12-29 09:14:28 +01:00
let VerifiableServerBatchEvaluatePrepareResult {
prepared_evaluation_elements,
t,
} = server
.batch_evaluate_prepare(client_messages.iter(), Some(info))
.unwrap();
let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
let VerifiableServerBatchEvaluateFinishResult { messages, proof } =
VerifiableServer::batch_evaluate_finish(
&mut rng,
client_messages.iter(),
&prepared_elements,
&t,
)
.unwrap();
2021-12-29 09:14:28 +01:00
let messages: Vec<_> = messages.collect();
let client_finalize_result = VerifiableClient::batch_finalize(
2021-12-23 21:03:38 +01:00
&inputs,
&client_states,
2021-12-29 09:14:28 +01:00
&messages,
&proof,
server.get_public_key(),
Some(info),
)
2021-12-23 21:03:38 +01:00
.unwrap()
2021-12-25 22:54:27 +01:00
.collect::<Result<Vec<_>>>()
.unwrap();
let mut res2 = vec![];
2021-10-06 00:19:20 +02:00
for input in inputs.iter().take(num_iterations) {
2022-01-21 22:52:09 +01:00
let output = prf::<CS>(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);
}
2022-01-21 22:52:09 +01:00
fn verifiable_batch_bad_public_key<CS: CipherSuite>()
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
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 {
2021-12-23 21:03:38 +01:00
let mut input = [0u8; 32];
rng.fill_bytes(&mut input);
2022-01-21 22:52:09 +01:00
let client_blind_result = VerifiableClient::<CS>::blind(&input, &mut rng).unwrap();
inputs.push(input);
client_states.push(client_blind_result.state);
client_messages.push(client_blind_result.message);
}
2022-01-25 05:55:02 +01:00
let server = VerifiableServer::<CS>::new(&mut rng);
2021-12-29 09:14:28 +01:00
let VerifiableServerBatchEvaluatePrepareResult {
prepared_evaluation_elements,
t,
} = server
.batch_evaluate_prepare(client_messages.iter(), Some(info))
.unwrap();
2021-12-29 09:14:28 +01:00
let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
let VerifiableServerBatchEvaluateFinishResult { messages, proof } =
VerifiableServer::batch_evaluate_finish(
&mut rng,
client_messages.iter(),
&prepared_elements,
&t,
)
.unwrap();
let messages: Vec<_> = messages.collect();
let wrong_pk = {
// Choose a group element that is unlikely to be the right public key
2022-01-21 22:52:09 +01:00
CS::Group::hash_to_curve::<CS>(&[b"msg"], Mode::Base).unwrap()
};
let client_finalize_result = VerifiableClient::batch_finalize(
2021-12-23 21:03:38 +01:00
&inputs,
&client_states,
2021-12-29 09:14:28 +01:00
&messages,
&proof,
wrong_pk,
Some(info),
);
assert!(client_finalize_result.is_err());
}
2022-01-21 22:52:09 +01:00
fn base_inversion_unsalted<CS: CipherSuite>()
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-09-09 01:56:54 -07:00
let mut rng = OsRng;
2021-12-23 21:03:38 +01:00
let mut input = [0u8; 64];
2021-09-09 01:56:54 -07:00
rng.fill_bytes(&mut input);
let info = b"info";
2022-01-21 22:52:09 +01:00
let client_blind_result = NonVerifiableClient::<CS>::blind(&input, &mut rng).unwrap();
2021-09-20 00:17:53 -07:00
let client_finalize_result = client_blind_result
.state
.finalize(
2021-12-23 21:03:38 +01:00
&input,
2022-01-21 22:52:09 +01:00
&EvaluationElement(client_blind_result.message.0),
Some(info),
2021-09-20 00:17:53 -07:00
)
.unwrap();
2021-09-09 01:56:54 -07:00
2022-01-21 22:52:09 +01:00
let point = CS::Group::hash_to_curve::<CS>(&[&input], Mode::Base).unwrap();
let res2 = finalize_after_unblind::<CS, _, _>(
2022-01-25 05:55:02 +01:00
iter::once((input.as_ref(), point)),
info,
Mode::Base,
)
2021-12-23 21:03:38 +01:00
.next()
.unwrap()
.unwrap();
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
2022-01-21 22:52:09 +01:00
fn zeroize_base_client<CS: CipherSuite>()
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-10-11 02:51:12 +02:00
let input = b"input";
let mut rng = OsRng;
2022-01-21 22:52:09 +01:00
let client_blind_result = NonVerifiableClient::<CS>::blind(input, &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
}
2022-01-21 22:52:09 +01:00
fn zeroize_verifiable_client<CS: CipherSuite>()
2021-12-23 21:03:38 +01:00
where
2022-01-21 22:52:09 +01:00
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
<CS::Group as Group>::ScalarLen: Add<<CS::Group as Group>::ElemLen>,
Sum<<CS::Group as Group>::ScalarLen, <CS::Group as Group>::ElemLen>: ArrayLength<u8>,
2021-12-23 21:03:38 +01:00
{
2021-10-11 02:51:12 +02:00
let input = b"input";
let mut rng = OsRng;
2022-01-21 22:52:09 +01:00
let client_blind_result = VerifiableClient::<CS>::blind(input, &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
}
2022-01-21 22:52:09 +01:00
fn zeroize_base_server<CS: CipherSuite>()
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
2021-10-11 02:51:12 +02:00
let input = b"input";
let info = b"info";
let mut rng = OsRng;
2022-01-21 22:52:09 +01:00
let client_blind_result = NonVerifiableClient::<CS>::blind(input, &mut rng).unwrap();
2022-01-25 05:55:02 +01:00
let server = NonVerifiableServer::<CS>::new(&mut rng);
2022-01-28 01:38:17 +01:00
let message = server
2021-12-21 20:17:02 +01:00
.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
2022-01-28 01:38:17 +01:00
let mut message = message;
2021-10-11 02:51:12 +02:00
Zeroize::zeroize(&mut message);
assert!(message.serialize().iter().all(|&x| x == 0));
2021-10-11 02:51:12 +02:00
}
2022-01-21 22:52:09 +01:00
fn zeroize_verifiable_server<CS: CipherSuite>()
2021-12-23 21:03:38 +01:00
where
2022-01-21 22:52:09 +01:00
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
<CS::Group as Group>::ScalarLen: Add<<CS::Group as Group>::ElemLen>,
Sum<<CS::Group as Group>::ScalarLen, <CS::Group as Group>::ElemLen>: ArrayLength<u8>,
<CS::Group as Group>::ScalarLen: Add<<CS::Group as Group>::ScalarLen>,
Sum<<CS::Group as Group>::ScalarLen, <CS::Group as Group>::ScalarLen>: ArrayLength<u8>,
2021-12-23 21:03:38 +01:00
{
2021-10-11 02:51:12 +02:00
let input = b"input";
let info = b"info";
let mut rng = OsRng;
2022-01-21 22:52:09 +01:00
let client_blind_result = VerifiableClient::<CS>::blind(input, &mut rng).unwrap();
2022-01-25 05:55:02 +01:00
let server = VerifiableServer::<CS>::new(&mut rng);
2021-10-11 02:51:12 +02:00
let server_result = server
2021-12-21 20:17:02 +01:00
.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]
2021-12-25 22:54:27 +01:00
fn test_functionality() -> Result<()> {
2022-01-21 22:52:09 +01:00
use p256::NistP256;
2021-12-23 07:50:48 +01:00
#[cfg(feature = "ristretto255")]
{
2022-01-18 12:34:28 +01:00
use crate::Ristretto255;
2022-01-21 22:52:09 +01:00
base_retrieval::<Ristretto255>();
base_inversion_unsalted::<Ristretto255>();
verifiable_retrieval::<Ristretto255>();
verifiable_batch_retrieval::<Ristretto255>();
verifiable_bad_public_key::<Ristretto255>();
verifiable_batch_bad_public_key::<Ristretto255>();
zeroize_base_client::<Ristretto255>();
zeroize_base_server::<Ristretto255>();
zeroize_verifiable_client::<Ristretto255>();
zeroize_verifiable_server::<Ristretto255>();
2021-12-23 07:50:48 +01:00
}
2021-10-11 02:51:12 +02:00
2022-01-21 22:52:09 +01:00
base_retrieval::<NistP256>();
base_inversion_unsalted::<NistP256>();
verifiable_retrieval::<NistP256>();
verifiable_batch_retrieval::<NistP256>();
verifiable_bad_public_key::<NistP256>();
verifiable_batch_bad_public_key::<NistP256>();
zeroize_base_client::<NistP256>();
zeroize_base_server::<NistP256>();
zeroize_verifiable_client::<NistP256>();
zeroize_verifiable_server::<NistP256>();
2021-09-28 19:44:57 -07:00
Ok(())
}
2021-09-09 01:56:54 -07:00
}