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;
|
2022-01-18 12:34:28 +01:00
|
|
|
use core::convert::{TryFrom, TryInto};
|
2021-12-23 21:03:38 +01:00
|
|
|
use core::iter::{self, Map, Repeat, Zip};
|
2021-10-06 00:53:18 +02:00
|
|
|
use core::marker::PhantomData;
|
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-04 00:45:05 +01:00
|
|
|
use digest::{Digest, FixedOutputReset, Output};
|
2021-10-13 00:07:47 +02:00
|
|
|
use generic_array::sequence::Concat;
|
2022-01-18 12:34:28 +01:00
|
|
|
use generic_array::typenum::{Unsigned, U11, U20};
|
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-18 12:34:28 +01:00
|
|
|
use crate::util::{i2osp_2, i2osp_2_array};
|
2021-12-25 22:54:27 +01:00
|
|
|
use crate::{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`].
|
2021-09-29 17:02:40 -07:00
|
|
|
#[derive(Clone, Copy)]
|
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))]
|
|
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Scalar)]
|
2021-12-23 21:03:38 +01:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serde",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
|
|
|
|
serde(bound(
|
|
|
|
|
deserialize = "G::Scalar: serde::Deserialize<'de>",
|
|
|
|
|
serialize = "G::Scalar: serde::Serialize"
|
|
|
|
|
))
|
|
|
|
|
)]
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct NonVerifiableClient<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
2021-12-21 20:17:02 +01:00
|
|
|
pub(crate) blind: G::Scalar,
|
|
|
|
|
#[derive_where(skip(Zeroize))]
|
|
|
|
|
pub(crate) hash: PhantomData<H>,
|
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-18 12:34:28 +01:00
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Elem, G::Scalar)]
|
2021-12-23 21:03:38 +01:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serde",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
|
|
|
|
serde(bound(
|
2022-01-18 12:34:28 +01:00
|
|
|
deserialize = "G::Scalar: serde::Deserialize<'de>, G::Elem: serde::Deserialize<'de>",
|
|
|
|
|
serialize = "G::Scalar: serde::Serialize, G::Elem: serde::Serialize"
|
2021-12-23 21:03:38 +01:00
|
|
|
))
|
|
|
|
|
)]
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct VerifiableClient<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
2021-12-21 20:17:02 +01:00
|
|
|
pub(crate) blind: G::Scalar,
|
2022-01-18 12:34:28 +01:00
|
|
|
pub(crate) blinded_element: G::Elem,
|
2021-12-21 20:17:02 +01:00
|
|
|
#[derive_where(skip(Zeroize))]
|
|
|
|
|
pub(crate) hash: PhantomData<H>,
|
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))]
|
|
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Scalar)]
|
2021-12-23 21:03:38 +01:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serde",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
|
|
|
|
serde(bound(
|
|
|
|
|
deserialize = "G::Scalar: serde::Deserialize<'de>",
|
|
|
|
|
serialize = "G::Scalar: serde::Serialize"
|
|
|
|
|
))
|
|
|
|
|
)]
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct NonVerifiableServer<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
2021-12-21 20:17:02 +01:00
|
|
|
pub(crate) sk: G::Scalar,
|
|
|
|
|
#[derive_where(skip(Zeroize))]
|
|
|
|
|
pub(crate) hash: PhantomData<H>,
|
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-18 12:34:28 +01:00
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Elem, G::Scalar)]
|
2021-12-23 21:03:38 +01:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serde",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
|
|
|
|
serde(bound(
|
2022-01-18 12:34:28 +01:00
|
|
|
deserialize = "G::Scalar: serde::Deserialize<'de>, G::Elem: serde::Deserialize<'de>",
|
|
|
|
|
serialize = "G::Scalar: serde::Serialize, G::Elem: serde::Serialize"
|
2021-12-23 21:03:38 +01:00
|
|
|
))
|
|
|
|
|
)]
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct VerifiableServer<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
2021-12-21 20:17:02 +01:00
|
|
|
pub(crate) sk: G::Scalar,
|
2022-01-18 12:34:28 +01:00
|
|
|
pub(crate) pk: G::Elem,
|
2021-12-21 20:17:02 +01:00
|
|
|
#[derive_where(skip(Zeroize))]
|
|
|
|
|
pub(crate) hash: PhantomData<H>,
|
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))]
|
|
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Scalar)]
|
2021-12-23 21:03:38 +01:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serde",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
|
|
|
|
serde(bound(
|
|
|
|
|
deserialize = "G::Scalar: serde::Deserialize<'de>",
|
|
|
|
|
serialize = "G::Scalar: serde::Serialize"
|
|
|
|
|
))
|
|
|
|
|
)]
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct Proof<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
2021-12-21 20:17:02 +01:00
|
|
|
pub(crate) c_scalar: G::Scalar,
|
|
|
|
|
pub(crate) s_scalar: G::Scalar,
|
|
|
|
|
#[derive_where(skip(Zeroize))]
|
|
|
|
|
pub(crate) hash: PhantomData<H>,
|
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-18 12:34:28 +01:00
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Elem)]
|
2021-12-23 21:03:38 +01:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serde",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
|
|
|
|
serde(bound(
|
2022-01-18 12:34:28 +01:00
|
|
|
deserialize = "G::Elem: serde::Deserialize<'de>",
|
|
|
|
|
serialize = "G::Elem: serde::Serialize"
|
2021-12-23 21:03:38 +01:00
|
|
|
))
|
|
|
|
|
)]
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct BlindedElement<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
2022-01-18 12:34:28 +01:00
|
|
|
pub(crate) value: G::Elem,
|
2021-12-21 20:17:02 +01:00
|
|
|
#[derive_where(skip(Zeroize))]
|
|
|
|
|
pub(crate) hash: PhantomData<H>,
|
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-18 12:34:28 +01:00
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Elem)]
|
2021-12-23 21:03:38 +01:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serde",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
|
|
|
|
serde(bound(
|
2022-01-18 12:34:28 +01:00
|
|
|
deserialize = "G::Elem: serde::Deserialize<'de>",
|
|
|
|
|
serialize = "G::Elem: serde::Serialize"
|
2021-12-23 21:03:38 +01:00
|
|
|
))
|
|
|
|
|
)]
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct EvaluationElement<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
2022-01-18 12:34:28 +01:00
|
|
|
pub(crate) value: G::Elem,
|
2021-12-21 20:17:02 +01:00
|
|
|
#[derive_where(skip(Zeroize))]
|
|
|
|
|
pub(crate) hash: PhantomData<H>,
|
2021-10-11 02:51:12 +02:00
|
|
|
}
|
2021-09-15 17:49:31 -07:00
|
|
|
|
|
|
|
|
/////////////////////////
|
|
|
|
|
// API Implementations //
|
|
|
|
|
// =================== //
|
|
|
|
|
/////////////////////////
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> NonVerifiableClient<G, H> {
|
2021-12-23 01:17:03 +01:00
|
|
|
/// Computes the first step for the multiplicative blinding version of
|
|
|
|
|
/// DH-OPRF.
|
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,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<NonVerifiableClientBlindResult<G, H>> {
|
2021-12-23 21:03:38 +01:00
|
|
|
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 {
|
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
|
|
|
}
|
|
|
|
|
|
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.
|
2021-10-18 13:24:15 -07:00
|
|
|
///
|
|
|
|
|
/// # 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!
|
2021-10-18 13:24:15 -07:00
|
|
|
pub fn deterministic_blind_unchecked(
|
2021-12-23 21:03:38 +01:00
|
|
|
input: &[u8],
|
2021-12-21 20:17:02 +01:00
|
|
|
blind: G::Scalar,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<NonVerifiableClientBlindResult<G, H>> {
|
2021-12-23 21:03:38 +01:00
|
|
|
let blinded_element = deterministic_blind_unchecked::<G, H>(input, &blind, Mode::Base)?;
|
2021-10-18 13:24:15 -07:00
|
|
|
Ok(NonVerifiableClientBlindResult {
|
|
|
|
|
state: Self {
|
|
|
|
|
blind,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
},
|
|
|
|
|
message: BlindedElement {
|
|
|
|
|
value: blinded_element,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
2021-09-09 01:56:54 -07:00
|
|
|
pub fn finalize(
|
|
|
|
|
&self,
|
2021-12-23 21:03:38 +01:00
|
|
|
input: &[u8],
|
2021-12-21 20:17:02 +01:00
|
|
|
evaluation_element: &EvaluationElement<G, H>,
|
2021-10-13 00:07:47 +02:00
|
|
|
metadata: Option<&[u8]>,
|
2022-01-04 00:45:05 +01:00
|
|
|
) -> Result<Output<H>> {
|
2022-01-18 12:34:28 +01:00
|
|
|
let unblinded_element = evaluation_element.value * &G::invert_scalar(self.blind);
|
2021-12-23 21:03:38 +01:00
|
|
|
let mut outputs = finalize_after_unblind::<G, H, _, _>(
|
|
|
|
|
Some((input, unblinded_element)).into_iter(),
|
2021-10-13 00:07:47 +02:00
|
|
|
metadata.unwrap_or_default(),
|
2021-09-15 11:38:13 -07:00
|
|
|
Mode::Base,
|
|
|
|
|
)?;
|
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
|
2021-12-23 21:03:38 +01:00
|
|
|
pub fn from_blind(blind: G::Scalar) -> Self {
|
2021-09-09 01:56:54 -07:00
|
|
|
Self {
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-14 13:55:43 -07:00
|
|
|
#[cfg(feature = "danger")]
|
|
|
|
|
/// Exposes the blind group element
|
2021-12-21 20:17:02 +01:00
|
|
|
pub fn get_blind(&self) -> G::Scalar {
|
2021-09-09 01:56:54 -07:00
|
|
|
self.blind
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> VerifiableClient<G, H> {
|
2021-12-23 01:17:03 +01:00
|
|
|
/// Computes the first step for the multiplicative blinding version of
|
|
|
|
|
/// DH-OPRF.
|
2021-09-13 16:02:09 -07:00
|
|
|
pub fn blind<R: RngCore + CryptoRng>(
|
2021-12-23 21:03:38 +01:00
|
|
|
input: &[u8],
|
2021-09-13 16:02:09 -07:00
|
|
|
blinding_factor_rng: &mut R,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<VerifiableClientBlindResult<G, H>> {
|
2021-09-15 11:38:13 -07:00
|
|
|
let (blind, blinded_element) =
|
2021-12-23 21:03:38 +01:00
|
|
|
blind::<G, H, _>(input, blinding_factor_rng, Mode::Verifiable)?;
|
2021-09-20 00:17:53 -07:00
|
|
|
Ok(VerifiableClientBlindResult {
|
|
|
|
|
state: Self {
|
2021-09-13 16:02:09 -07:00
|
|
|
blind,
|
|
|
|
|
blinded_element,
|
2021-10-06 00:53:18 +02:00
|
|
|
hash: PhantomData,
|
2021-09-13 16:02:09 -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-13 16:02:09 -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.
|
2021-10-18 13:24:15 -07:00
|
|
|
///
|
|
|
|
|
/// # 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!
|
2021-10-18 13:24:15 -07:00
|
|
|
pub fn deterministic_blind_unchecked(
|
2021-12-23 21:03:38 +01:00
|
|
|
input: &[u8],
|
2021-12-21 20:17:02 +01:00
|
|
|
blind: G::Scalar,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<VerifiableClientBlindResult<G, H>> {
|
2021-10-18 13:24:15 -07:00
|
|
|
let blinded_element =
|
2021-12-23 21:03:38 +01:00
|
|
|
deterministic_blind_unchecked::<G, H>(input, &blind, Mode::Verifiable)?;
|
2021-10-18 13:24:15 -07:00
|
|
|
Ok(VerifiableClientBlindResult {
|
|
|
|
|
state: Self {
|
|
|
|
|
blind,
|
|
|
|
|
blinded_element,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
},
|
|
|
|
|
message: BlindedElement {
|
|
|
|
|
value: blinded_element,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
2021-09-13 16:02:09 -07:00
|
|
|
pub fn finalize(
|
|
|
|
|
&self,
|
2021-12-23 21:03:38 +01:00
|
|
|
input: &[u8],
|
2021-12-21 20:17:02 +01:00
|
|
|
evaluation_element: &EvaluationElement<G, H>,
|
|
|
|
|
proof: &Proof<G, H>,
|
2022-01-18 12:34:28 +01:00
|
|
|
pk: G::Elem,
|
2021-10-13 00:07:47 +02:00
|
|
|
metadata: Option<&[u8]>,
|
2022-01-04 00:45:05 +01:00
|
|
|
) -> Result<Output<H>> {
|
2021-12-21 20:17:02 +01:00
|
|
|
// `core::array::from_ref` needs a MSRV of 1.53
|
2021-12-23 21:03:38 +01:00
|
|
|
let inputs: &[&[u8]; 1] = core::slice::from_ref(&input).try_into().unwrap();
|
2021-10-13 00:07:47 +02:00
|
|
|
let clients: &[Self; 1] = core::slice::from_ref(self).try_into().unwrap();
|
2021-12-21 20:17:02 +01:00
|
|
|
let messages: &[EvaluationElement<G, H>; 1] = core::slice::from_ref(evaluation_element)
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
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-09-15 11:38:13 -07:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 01:17:03 +01:00
|
|
|
/// Allows for batching of the finalization of multiple [VerifiableClient]
|
|
|
|
|
/// and [EvaluationElement] pairs
|
2021-12-23 21:03:38 +01:00
|
|
|
pub fn batch_finalize<'a, I: 'a, II, IC, IM>(
|
|
|
|
|
inputs: &'a II,
|
2021-10-13 00:07:47 +02:00
|
|
|
clients: &'a IC,
|
|
|
|
|
messages: &'a IM,
|
2021-12-21 20:17:02 +01:00
|
|
|
proof: &Proof<G, H>,
|
2022-01-18 12:34:28 +01:00
|
|
|
pk: G::Elem,
|
2021-12-23 21:03:38 +01:00
|
|
|
metadata: Option<&'a [u8]>,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<VerifiableClientBatchFinalizeResult<'a, G, H, I, II, IC, IM>>
|
2021-10-13 00:07:47 +02:00
|
|
|
where
|
|
|
|
|
G: 'a,
|
|
|
|
|
H: 'a,
|
2021-12-23 21:03:38 +01:00
|
|
|
I: AsRef<[u8]>,
|
|
|
|
|
&'a II: 'a + IntoIterator<Item = I>,
|
|
|
|
|
<&'a II as IntoIterator>::IntoIter: ExactSizeIterator,
|
2021-10-13 00:07:47 +02:00
|
|
|
&'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,
|
|
|
|
|
{
|
|
|
|
|
let metadata = metadata.unwrap_or_default();
|
2021-09-15 11:38:13 -07:00
|
|
|
|
2021-12-23 21:03:38 +01:00
|
|
|
let unblinded_elements = verifiable_unblind(clients, messages, pk, proof, metadata)?;
|
2021-09-15 11:38:13 -07:00
|
|
|
|
2021-12-23 21:03:38 +01:00
|
|
|
let inputs_and_unblinded_elements = inputs.into_iter().zip(unblinded_elements);
|
2021-09-15 11:38:13 -07:00
|
|
|
|
2021-12-23 21:03:38 +01:00
|
|
|
finalize_after_unblind::<G, H, _, _>(
|
|
|
|
|
inputs_and_unblinded_elements,
|
|
|
|
|
metadata,
|
|
|
|
|
Mode::Verifiable,
|
|
|
|
|
)
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
/// Only used for test functions
|
2022-01-18 12:34:28 +01:00
|
|
|
pub fn from_blind_and_element(blind: G::Scalar, blinded_element: G::Elem) -> Self {
|
2021-09-13 16:02:09 -07:00
|
|
|
Self {
|
2021-10-06 00:19:20 +02:00
|
|
|
blind,
|
|
|
|
|
blinded_element,
|
2021-10-06 00:53:18 +02:00
|
|
|
hash: PhantomData,
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
/// Only used for test functions
|
2021-12-21 20:17:02 +01:00
|
|
|
pub fn get_blind(&self) -> G::Scalar {
|
2021-09-13 16:02:09 -07:00
|
|
|
self.blind
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> NonVerifiableServer<G, H> {
|
2021-09-15 17:49:31 -07:00
|
|
|
/// Produces a new instance of a [NonVerifiableServer] using a supplied RNG
|
2021-12-25 22:54:27 +01:00
|
|
|
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self> {
|
2022-01-04 00:45:05 +01:00
|
|
|
let mut seed = Output::<H>::default();
|
2021-09-13 16:02:09 -07:00
|
|
|
rng.fill_bytes(&mut seed);
|
|
|
|
|
Self::new_from_seed(&seed)
|
|
|
|
|
}
|
|
|
|
|
|
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
|
2021-12-25 22:54:27 +01:00
|
|
|
pub fn new_with_key(private_key_bytes: &[u8]) -> Result<Self> {
|
2022-01-18 12:34:28 +01:00
|
|
|
let sk = G::deserialize_scalar(private_key_bytes.into())?;
|
2021-10-06 00:53:18 +02:00
|
|
|
Ok(Self {
|
|
|
|
|
sk,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
})
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
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.
|
2021-12-25 22:54:27 +01:00
|
|
|
pub fn new_from_seed(seed: &[u8]) -> Result<Self> {
|
2022-01-18 12:34:28 +01:00
|
|
|
let sk = G::hash_to_scalar::<H>(&[seed], Mode::Base)?;
|
2021-10-06 00:53:18 +02:00
|
|
|
Ok(Self {
|
|
|
|
|
sk,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
})
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-15 11:38:13 -07:00
|
|
|
// Only used for tests
|
|
|
|
|
#[cfg(test)]
|
2021-10-06 00:53:18 +02:00
|
|
|
pub fn get_private_key(&self) -> <G>::Scalar {
|
2021-09-15 11:38:13 -07:00
|
|
|
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.
|
2021-09-13 16:02:09 -07:00
|
|
|
pub fn evaluate(
|
|
|
|
|
&self,
|
2021-12-21 20:17:02 +01:00
|
|
|
blinded_element: &BlindedElement<G, H>,
|
2021-10-13 00:07:47 +02:00
|
|
|
metadata: Option<&[u8]>,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<NonVerifiableServerEvaluateResult<G, H>> {
|
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
|
|
|
|
|
|
|
|
|
|
let context_string = get_context_string::<G>(Mode::Base);
|
|
|
|
|
let metadata = metadata.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
// context = "Context-" || contextString || I2OSP(len(info), 2) || info
|
|
|
|
|
let context = GenericArray::from(STR_CONTEXT)
|
|
|
|
|
.concat(context_string)
|
|
|
|
|
.concat(i2osp_2(metadata.len())?);
|
|
|
|
|
let context = [&context, metadata];
|
|
|
|
|
|
|
|
|
|
// m = GG.HashToScalar(context)
|
|
|
|
|
let m = G::hash_to_scalar::<H>(&context, Mode::Base)?;
|
|
|
|
|
// t = skS + m
|
2021-09-13 16:02:09 -07:00
|
|
|
let t = self.sk + &m;
|
2022-01-18 12:34:28 +01:00
|
|
|
// Z = t^(-1) * R
|
|
|
|
|
let z = blinded_element.value * &G::invert_scalar(t);
|
|
|
|
|
|
2021-09-20 00:17:53 -07:00
|
|
|
Ok(NonVerifiableServerEvaluateResult {
|
2021-09-28 19:44:57 -07:00
|
|
|
message: EvaluationElement {
|
2022-01-18 12:34:28 +01:00
|
|
|
value: z,
|
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-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> VerifiableServer<G, H> {
|
2021-09-15 17:49:31 -07:00
|
|
|
/// Produces a new instance of a [VerifiableServer] using a supplied RNG
|
2021-12-25 22:54:27 +01:00
|
|
|
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self> {
|
2022-01-04 00:45:05 +01:00
|
|
|
let mut seed = Output::<H>::default();
|
2021-09-13 16:02:09 -07:00
|
|
|
rng.fill_bytes(&mut seed);
|
|
|
|
|
Self::new_from_seed(&seed)
|
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
|
2021-12-25 22:54:27 +01:00
|
|
|
pub fn new_with_key(key: &[u8]) -> Result<Self> {
|
2022-01-18 12:34:28 +01:00
|
|
|
let sk = G::deserialize_scalar(key.into())?;
|
|
|
|
|
let pk = G::base_elem() * &sk;
|
2021-10-06 00:53:18 +02:00
|
|
|
Ok(Self {
|
|
|
|
|
sk,
|
|
|
|
|
pk,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
})
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
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.
|
2021-12-25 22:54:27 +01:00
|
|
|
pub fn new_from_seed(seed: &[u8]) -> Result<Self> {
|
2022-01-18 12:34:28 +01:00
|
|
|
let sk = G::hash_to_scalar::<H>(&[seed], Mode::Verifiable)?;
|
|
|
|
|
let pk = G::base_elem() * &sk;
|
2021-10-06 00:53:18 +02:00
|
|
|
Ok(Self {
|
|
|
|
|
sk,
|
|
|
|
|
pk,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
})
|
2021-09-09 01:56:54 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-15 11:38:13 -07:00
|
|
|
// Only used for tests
|
|
|
|
|
#[cfg(test)]
|
2021-12-21 20:17:02 +01:00
|
|
|
pub fn get_private_key(&self) -> G::Scalar {
|
2021-09-15 11:38:13 -07:00
|
|
|
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.
|
2021-09-13 16:02:09 -07:00
|
|
|
pub fn evaluate<R: RngCore + CryptoRng>(
|
|
|
|
|
&self,
|
|
|
|
|
rng: &mut R,
|
2021-12-21 20:17:02 +01:00
|
|
|
blinded_element: &BlindedElement<G, H>,
|
2021-10-13 00:07:47 +02:00
|
|
|
metadata: Option<&[u8]>,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<VerifiableServerEvaluateResult<G, H>> {
|
2021-12-29 09:14:28 +01:00
|
|
|
let VerifiableServerBatchEvaluatePrepareResult {
|
|
|
|
|
prepared_evaluation_elements: mut evaluation_elements,
|
|
|
|
|
t,
|
|
|
|
|
} = self.batch_evaluate_prepare(Some(blinded_element).into_iter(), 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
|
|
|
|
2021-12-29 09:14:28 +01:00
|
|
|
let VerifiableServerBatchEvaluateFinishResult {
|
|
|
|
|
mut messages,
|
|
|
|
|
proof,
|
|
|
|
|
} = Self::batch_evaluate_finish(
|
2021-12-23 21:03:38 +01:00
|
|
|
rng,
|
2021-12-29 09:14:28 +01:00
|
|
|
Some(blinded_element).into_iter(),
|
|
|
|
|
&prepared_element,
|
|
|
|
|
&t,
|
2021-12-23 21:03:38 +01:00
|
|
|
)?;
|
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-09-15 11:38:13 -07:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 01:17:03 +01:00
|
|
|
/// Allows for batching of the evaluation of multiple [BlindedElement]
|
|
|
|
|
/// messages from a [VerifiableClient]
|
2021-12-23 21:03:38 +01:00
|
|
|
#[cfg(feature = "alloc")]
|
2021-10-13 00:07:47 +02:00
|
|
|
pub fn batch_evaluate<'a, R: RngCore + CryptoRng, I>(
|
2021-09-15 11:38:13 -07:00
|
|
|
&self,
|
|
|
|
|
rng: &mut R,
|
2021-10-13 00:07:47 +02:00
|
|
|
blinded_elements: &'a I,
|
|
|
|
|
metadata: Option<&[u8]>,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<VerifiableServerBatchEvaluateResult<G, H>>
|
2021-10-13 00:07:47 +02:00
|
|
|
where
|
|
|
|
|
G: 'a,
|
|
|
|
|
H: 'a,
|
|
|
|
|
&'a I: IntoIterator<Item = &'a BlindedElement<G, H>>,
|
|
|
|
|
<&'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
|
|
|
|
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,
|
|
|
|
|
)?;
|
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).
|
|
|
|
|
pub fn batch_evaluate_prepare<'a, I: Iterator<Item = &'a BlindedElement<G, H>>>(
|
2021-12-23 21:03:38 +01:00
|
|
|
&self,
|
|
|
|
|
blinded_elements: I,
|
|
|
|
|
metadata: Option<&[u8]>,
|
2021-12-29 09:14:28 +01:00
|
|
|
) -> Result<VerifiableServerBatchEvaluatePrepareResult<'a, G, H, 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
|
|
|
|
|
|
|
|
|
|
let context_string = get_context_string::<G>(Mode::Verifiable);
|
|
|
|
|
let metadata = metadata.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
// context = "Context-" || contextString || I2OSP(len(info), 2) || info
|
|
|
|
|
let context = GenericArray::from(STR_CONTEXT)
|
|
|
|
|
.concat(context_string)
|
|
|
|
|
.concat(i2osp_2(metadata.len())?);
|
|
|
|
|
let context = [&context, metadata];
|
|
|
|
|
|
|
|
|
|
let m = G::hash_to_scalar::<H>(&context, Mode::Verifiable)?;
|
2021-09-13 16:02:09 -07:00
|
|
|
let t = self.sk + &m;
|
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-18 12:34:28 +01:00
|
|
|
.zip(iter::repeat(G::invert_scalar(t)))
|
2021-12-29 09:14:28 +01:00
|
|
|
.map(<fn((&BlindedElement<G, H>, _)) -> _>::from(|(x, t)| {
|
|
|
|
|
PreparedEvaluationElement(EvaluationElement {
|
|
|
|
|
value: x.value * &t,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
})
|
|
|
|
|
}));
|
2021-09-13 16:02:09 -07:00
|
|
|
|
2021-12-29 09:14:28 +01:00
|
|
|
Ok(VerifiableServerBatchEvaluatePrepareResult {
|
|
|
|
|
prepared_evaluation_elements: evaluation_elements,
|
|
|
|
|
t: PreparedTscalar {
|
|
|
|
|
t,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
},
|
|
|
|
|
})
|
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.
|
|
|
|
|
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,
|
|
|
|
|
PreparedTscalar { t, .. }: &PreparedTscalar<G, H>,
|
|
|
|
|
) -> Result<VerifiableServerBatchEvaluateFinishResult<'b, G, H, IE>>
|
2021-12-23 21:03:38 +01:00
|
|
|
where
|
2021-12-29 09:14:28 +01:00
|
|
|
G: 'a + 'b,
|
|
|
|
|
H: 'a + 'b,
|
|
|
|
|
IB: Iterator<Item = &'a BlindedElement<G, H>> + ExactSizeIterator,
|
|
|
|
|
&'b IE: IntoIterator<Item = &'b PreparedEvaluationElement<G, H>>,
|
|
|
|
|
<&'b IE as IntoIterator>::IntoIter: ExactSizeIterator,
|
2021-12-23 21:03:38 +01:00
|
|
|
{
|
2022-01-18 12:34:28 +01:00
|
|
|
let g = G::base_elem();
|
2021-12-29 09:14:28 +01:00
|
|
|
let u = g * t;
|
2021-09-13 16:02:09 -07:00
|
|
|
|
2021-12-29 09:14:28 +01:00
|
|
|
let proof = generate_proof(
|
|
|
|
|
rng,
|
|
|
|
|
*t,
|
|
|
|
|
g,
|
|
|
|
|
u,
|
|
|
|
|
evaluation_elements
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|element| element.0.copy()),
|
|
|
|
|
blinded_elements.map(BlindedElement::copy),
|
|
|
|
|
)?;
|
|
|
|
|
let messages =
|
|
|
|
|
evaluation_elements
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(<fn(&PreparedEvaluationElement<G, H>) -> _>::from(
|
|
|
|
|
|element| element.0.copy(),
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
Ok(VerifiableServerBatchEvaluateFinishResult { messages, proof })
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-15 17:49:31 -07:00
|
|
|
/// Retrieves the server's public key
|
2022-01-18 12:34:28 +01:00
|
|
|
pub fn get_public_key(&self) -> G::Elem {
|
2021-09-13 16:02:09 -07:00
|
|
|
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-12-23 21:58:00 +01:00
|
|
|
pub struct NonVerifiableClientBlindResult<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
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-12-23 21:58:00 +01:00
|
|
|
pub struct NonVerifiableServerEvaluateResult<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>
|
|
|
|
|
{
|
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-12-23 21:58:00 +01:00
|
|
|
pub struct VerifiableClientBlindResult<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
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
|
|
|
}
|
|
|
|
|
|
2021-12-25 22:54:27 +01:00
|
|
|
/// Concrete return type for [`VerifiableClient::batch_finalize`].
|
2021-12-23 21:03:38 +01:00
|
|
|
pub type VerifiableClientBatchFinalizeResult<'a, G, H, I, II, IC, IM> = FinalizeAfterUnblindResult<
|
|
|
|
|
'a,
|
|
|
|
|
G,
|
|
|
|
|
H,
|
|
|
|
|
I,
|
|
|
|
|
Zip<<&'a II as IntoIterator>::IntoIter, VerifiableUnblindResult<'a, G, H, IC, IM>>,
|
|
|
|
|
>;
|
|
|
|
|
|
2021-09-20 00:17:53 -07:00
|
|
|
/// Contains the fields that are returned by a verifiable server evaluate
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct VerifiableServerEvaluateResult<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
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
|
|
|
}
|
|
|
|
|
|
2021-12-29 09:14:28 +01:00
|
|
|
/// Contains prepared [`EvaluationElement`]s by a verifiable server batch
|
|
|
|
|
/// evaluate preparation.
|
|
|
|
|
pub struct PreparedEvaluationElement<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
|
|
|
|
EvaluationElement<G, H>,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/// Contains the prepared `t` by a verifiable server batch evaluate preparation.
|
|
|
|
|
#[derive(DeriveWhere)]
|
|
|
|
|
#[derive_where(Zeroize(drop))]
|
|
|
|
|
pub struct PreparedTscalar<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
|
|
|
|
t: G::Scalar,
|
|
|
|
|
#[derive_where(skip)]
|
|
|
|
|
hash: PhantomData<H>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Contains the fields that are returned by a verifiable server batch evaluate
|
|
|
|
|
/// preparation.
|
|
|
|
|
pub struct VerifiableServerBatchEvaluatePrepareResult<
|
|
|
|
|
'a,
|
|
|
|
|
G: 'a + Group,
|
|
|
|
|
H: 'a + BlockSizeUser + Digest + FixedOutputReset,
|
|
|
|
|
I: Iterator<Item = &'a BlindedElement<G, H>>,
|
|
|
|
|
> {
|
|
|
|
|
/// Prepared [`EvaluationElement`]s that will become messages.
|
|
|
|
|
#[allow(clippy::type_complexity)]
|
|
|
|
|
pub prepared_evaluation_elements: Map<
|
|
|
|
|
Zip<I, Repeat<G::Scalar>>,
|
|
|
|
|
fn((&BlindedElement<G, H>, G::Scalar)) -> PreparedEvaluationElement<G, H>,
|
|
|
|
|
>,
|
|
|
|
|
/// Prepared `t` needed to finish the verifiable server batch evaluation.
|
|
|
|
|
pub t: PreparedTscalar<G, H>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Contains the fields that are returned by a verifiable server batch evaluate
|
|
|
|
|
/// finish.
|
|
|
|
|
pub struct VerifiableServerBatchEvaluateFinishResult<
|
|
|
|
|
'a,
|
|
|
|
|
G: 'a + Group,
|
|
|
|
|
H: 'a + BlockSizeUser + Digest + FixedOutputReset,
|
|
|
|
|
I,
|
|
|
|
|
> where
|
|
|
|
|
&'a I: IntoIterator<Item = &'a PreparedEvaluationElement<G, H>>,
|
|
|
|
|
{
|
|
|
|
|
/// The messages to send to the client
|
|
|
|
|
#[allow(clippy::type_complexity)]
|
|
|
|
|
pub messages: Map<
|
|
|
|
|
<&'a I as IntoIterator>::IntoIter,
|
|
|
|
|
fn(&PreparedEvaluationElement<G, H>) -> EvaluationElement<G, H>,
|
|
|
|
|
>,
|
|
|
|
|
/// The proof for the client to verify
|
|
|
|
|
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-12-23 21:03:38 +01:00
|
|
|
#[cfg(feature = "alloc")]
|
2021-12-23 21:58:00 +01:00
|
|
|
pub struct VerifiableServerBatchEvaluateResult<
|
|
|
|
|
G: Group,
|
|
|
|
|
H: BlockSizeUser + Digest + FixedOutputReset,
|
|
|
|
|
> {
|
2021-09-20 00:17:53 -07:00
|
|
|
/// The messages to send to the client
|
2021-12-23 21:03:38 +01:00
|
|
|
pub messages: alloc::vec::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 //
|
|
|
|
|
// ========================================= //
|
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> BlindedElement<G, H> {
|
2021-10-13 00:07:47 +02:00
|
|
|
/// Only used to easier validate allocation
|
|
|
|
|
fn copy(&self) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
value: self.value,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-14 13:55:43 -07:00
|
|
|
#[cfg(feature = "danger")]
|
|
|
|
|
/// Creates a [BlindedElement] from a raw group element.
|
|
|
|
|
///
|
|
|
|
|
/// # 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 value itself!
|
2022-01-18 12:34:28 +01:00
|
|
|
pub fn from_value_unchecked(value: G::Elem) -> Self {
|
2021-10-14 13:55:43 -07:00
|
|
|
Self {
|
|
|
|
|
value,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "danger")]
|
|
|
|
|
/// Exposes the internal value
|
2022-01-18 12:34:28 +01:00
|
|
|
pub fn value(&self) -> G::Elem {
|
2021-10-14 13:55:43 -07:00
|
|
|
self.value
|
2021-10-11 02:51:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> EvaluationElement<G, H> {
|
2021-10-13 00:07:47 +02:00
|
|
|
/// Only used to easier validate allocation
|
|
|
|
|
fn copy(&self) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
value: self.value,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-14 13:55:43 -07:00
|
|
|
#[cfg(feature = "danger")]
|
|
|
|
|
/// Creates an [EvaluationElement] from a raw group element.
|
|
|
|
|
///
|
|
|
|
|
/// # 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 value itself!
|
2022-01-18 12:34:28 +01:00
|
|
|
pub fn from_value_unchecked(value: G::Elem) -> Self {
|
2021-10-14 13:55:43 -07:00
|
|
|
Self {
|
|
|
|
|
value,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
}
|
2021-10-11 02:51:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-14 13:55:43 -07:00
|
|
|
#[cfg(feature = "danger")]
|
|
|
|
|
/// Exposes the internal value
|
2022-01-18 12:34:28 +01:00
|
|
|
pub fn value(&self) -> G::Elem {
|
2021-10-14 13:55:43 -07:00
|
|
|
self.value
|
2021-10-11 02:51:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-13 16:02:09 -07:00
|
|
|
// Inner function for blind. Returns the blind scalar and the blinded element
|
2021-12-23 21:58:00 +01:00
|
|
|
fn blind<G: Group, H: BlockSizeUser + Digest + FixedOutputReset, R: RngCore + CryptoRng>(
|
2021-09-13 16:02:09 -07:00
|
|
|
input: &[u8],
|
|
|
|
|
blinding_factor_rng: &mut R,
|
2021-09-15 11:38:13 -07:00
|
|
|
mode: Mode,
|
2022-01-18 12:34:28 +01:00
|
|
|
) -> Result<(G::Scalar, G::Elem)> {
|
2021-09-13 16:02:09 -07:00
|
|
|
// Choose a random scalar that must be non-zero
|
2022-01-18 12:34:28 +01:00
|
|
|
let blind = G::random_scalar(blinding_factor_rng);
|
2021-10-18 13:24:15 -07:00
|
|
|
let blinded_element = deterministic_blind_unchecked::<G, H>(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.
|
2021-12-23 21:58:00 +01:00
|
|
|
fn deterministic_blind_unchecked<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
2021-10-18 13:24:15 -07:00
|
|
|
input: &[u8],
|
2021-12-21 20:17:02 +01:00
|
|
|
blind: &G::Scalar,
|
2021-10-18 13:24:15 -07:00
|
|
|
mode: Mode,
|
2022-01-18 12:34:28 +01:00
|
|
|
) -> Result<G::Elem> {
|
|
|
|
|
let hashed_point = G::hash_to_curve::<H>(&[input], mode)?;
|
2021-10-18 13:24:15 -07:00
|
|
|
Ok(hashed_point * blind)
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:45:05 +01:00
|
|
|
type VerifiableUnblindResult<'a, G, H, 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,
|
|
|
|
|
fn(&VerifiableClient<G, H>) -> <G as Group>::Scalar,
|
|
|
|
|
>,
|
2021-12-23 21:03:38 +01:00
|
|
|
<&'a IM as IntoIterator>::IntoIter,
|
|
|
|
|
>,
|
2022-01-18 12:34:28 +01:00
|
|
|
fn((<G as Group>::Scalar, &EvaluationElement<G, H>)) -> <G as Group>::Elem,
|
2021-12-23 21:03:38 +01:00
|
|
|
>;
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn verifiable_unblind<
|
|
|
|
|
'a,
|
|
|
|
|
G: 'a + Group,
|
|
|
|
|
H: 'a + BlockSizeUser + Digest + FixedOutputReset,
|
|
|
|
|
IC,
|
|
|
|
|
IM,
|
|
|
|
|
>(
|
2021-12-23 21:03:38 +01:00
|
|
|
clients: &'a IC,
|
|
|
|
|
messages: &'a IM,
|
2022-01-18 12:34:28 +01:00
|
|
|
pk: G::Elem,
|
2021-12-21 20:17:02 +01:00
|
|
|
proof: &Proof<G, H>,
|
2021-09-15 17:49:31 -07:00
|
|
|
info: &[u8],
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<VerifiableUnblindResult<'a, G, H, IC, IM>>
|
2021-10-13 00:07:47 +02:00
|
|
|
where
|
2021-12-23 21:03:38 +01:00
|
|
|
&'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,
|
2021-10-13 00:07:47 +02:00
|
|
|
{
|
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
|
|
|
|
|
|
|
|
|
|
let context_string = get_context_string::<G>(Mode::Verifiable);
|
|
|
|
|
|
|
|
|
|
// context = "Context-" || contextString || I2OSP(len(info), 2) || info
|
|
|
|
|
let context = GenericArray::from(STR_CONTEXT)
|
|
|
|
|
.concat(context_string)
|
|
|
|
|
.concat(i2osp_2(info.len())?);
|
|
|
|
|
let context = [&context, info];
|
2021-09-15 17:49:31 -07:00
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
let m = G::hash_to_scalar::<H>(&context, Mode::Verifiable)?;
|
2021-09-15 17:49:31 -07:00
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
let g = G::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.
|
|
|
|
|
.map(<fn(&VerifiableClient<G, H>) -> _>::from(|x| x.blind));
|
|
|
|
|
let evaluation_elements = messages.into_iter().map(EvaluationElement::copy);
|
|
|
|
|
let blinded_elements = clients.into_iter().map(|client| BlindedElement {
|
|
|
|
|
value: client.blinded_element,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
});
|
2021-09-15 17:49:31 -07:00
|
|
|
|
2021-10-13 00:07:47 +02: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-18 12:34:28 +01:00
|
|
|
.map(|(blind, x)| x.value * &G::invert_scalar(blind)))
|
2021-09-15 17:49:31 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-13 16:02:09 -07:00
|
|
|
#[allow(clippy::many_single_char_names)]
|
2021-12-23 21:58:00 +01:00
|
|
|
fn generate_proof<
|
|
|
|
|
G: Group,
|
|
|
|
|
H: BlockSizeUser + Digest + FixedOutputReset,
|
|
|
|
|
R: RngCore + CryptoRng,
|
|
|
|
|
>(
|
2021-09-13 16:02:09 -07:00
|
|
|
rng: &mut R,
|
2021-12-21 20:17:02 +01:00
|
|
|
k: G::Scalar,
|
2022-01-18 12:34:28 +01:00
|
|
|
a: G::Elem,
|
|
|
|
|
b: G::Elem,
|
2021-10-13 00:07:47 +02:00
|
|
|
cs: impl Iterator<Item = EvaluationElement<G, H>> + ExactSizeIterator,
|
|
|
|
|
ds: impl Iterator<Item = BlindedElement<G, H>> + ExactSizeIterator,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<Proof<G, H>> {
|
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
|
|
|
|
|
|
2021-10-13 00:07:47 +02:00
|
|
|
let (m, z) = compute_composites(Some(k), b, cs, ds)?;
|
2021-10-06 00:53:18 +02:00
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
let r = G::random_scalar(rng);
|
2021-09-13 16:02:09 -07:00
|
|
|
let t2 = a * &r;
|
|
|
|
|
let t3 = m * &r;
|
|
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
// Bm = GG.SerializeElement(B)
|
|
|
|
|
let bm = G::serialize_elem(b);
|
|
|
|
|
// a0 = GG.SerializeElement(M)
|
|
|
|
|
let a0 = G::serialize_elem(m);
|
|
|
|
|
// a1 = GG.SerializeElement(Z)
|
|
|
|
|
let a1 = G::serialize_elem(z);
|
|
|
|
|
// a2 = GG.SerializeElement(t2)
|
|
|
|
|
let a2 = G::serialize_elem(t2);
|
|
|
|
|
// a3 = GG.SerializeElement(t3)
|
|
|
|
|
let a3 = G::serialize_elem(t3);
|
|
|
|
|
|
|
|
|
|
let elem_len = G::ElemLen::U16.to_be_bytes();
|
|
|
|
|
|
|
|
|
|
// challengeDST = "Challenge-" || contextString
|
2021-10-13 00:07:47 +02:00
|
|
|
let challenge_dst =
|
2022-01-18 12:34:28 +01:00
|
|
|
GenericArray::from(STR_CHALLENGE).concat(get_context_string::<G>(Mode::Verifiable));
|
|
|
|
|
let challenge_dst_len = i2osp_2_array(challenge_dst);
|
|
|
|
|
// 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,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let c_scalar = G::hash_to_scalar::<H>(&h2_input, Mode::Verifiable)?;
|
2021-09-15 11:38:13 -07:00
|
|
|
let s_scalar = r - &(c_scalar * &k);
|
2021-09-13 16:02:09 -07:00
|
|
|
|
2021-10-06 00:53:18 +02:00
|
|
|
Ok(Proof {
|
|
|
|
|
c_scalar,
|
|
|
|
|
s_scalar,
|
|
|
|
|
hash: PhantomData,
|
|
|
|
|
})
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(clippy::many_single_char_names)]
|
2021-12-23 21:58:00 +01:00
|
|
|
fn verify_proof<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
2022-01-18 12:34:28 +01:00
|
|
|
a: G::Elem,
|
|
|
|
|
b: G::Elem,
|
2021-10-13 00:07:47 +02:00
|
|
|
cs: impl Iterator<Item = EvaluationElement<G, H>> + ExactSizeIterator,
|
|
|
|
|
ds: impl Iterator<Item = BlindedElement<G, H>> + ExactSizeIterator,
|
2021-12-21 20:17:02 +01:00
|
|
|
proof: &Proof<G, H>,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<()> {
|
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
|
2021-10-13 00:07:47 +02:00
|
|
|
let (m, z) = compute_composites(None, b, cs, ds)?;
|
2021-09-13 16:02:09 -07:00
|
|
|
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)
|
|
|
|
|
let bm = G::serialize_elem(b);
|
|
|
|
|
// a0 = GG.SerializeElement(M)
|
|
|
|
|
let a0 = G::serialize_elem(m);
|
|
|
|
|
// a1 = GG.SerializeElement(Z)
|
|
|
|
|
let a1 = G::serialize_elem(z);
|
|
|
|
|
// a2 = GG.SerializeElement(t2)
|
|
|
|
|
let a2 = G::serialize_elem(t2);
|
|
|
|
|
// a3 = GG.SerializeElement(t3)
|
|
|
|
|
let a3 = G::serialize_elem(t3);
|
|
|
|
|
|
|
|
|
|
let elem_len = G::ElemLen::U16.to_be_bytes();
|
|
|
|
|
|
|
|
|
|
// challengeDST = "Challenge-" || contextString
|
2021-10-13 00:07:47 +02:00
|
|
|
let challenge_dst =
|
2022-01-18 12:34:28 +01:00
|
|
|
GenericArray::from(STR_CHALLENGE).concat(get_context_string::<G>(Mode::Verifiable));
|
|
|
|
|
let challenge_dst_len = i2osp_2_array(challenge_dst);
|
|
|
|
|
// 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,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let c = G::hash_to_scalar::<H>(&h2_input, Mode::Verifiable)?;
|
2021-09-13 16:02:09 -07:00
|
|
|
|
2021-10-14 20:09:00 +02:00
|
|
|
match c.ct_eq(&proof.c_scalar).into() {
|
2021-09-13 16:02:09 -07:00
|
|
|
true => Ok(()),
|
2021-12-25 22:54:27 +01:00
|
|
|
false => Err(Error::ProofVerificationError),
|
2021-09-09 01:56:54 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:45:05 +01:00
|
|
|
type FinalizeAfterUnblindResult<'a, G, H, I, IE> = Map<
|
2021-12-23 21:03:38 +01:00
|
|
|
Zip<IE, Repeat<(&'a [u8], GenericArray<u8, U20>)>>,
|
2022-01-18 12:34:28 +01:00
|
|
|
fn(((I, <G as Group>::Elem), (&'a [u8], GenericArray<u8, U20>))) -> Result<Output<H>>,
|
2021-12-23 21:03:38 +01:00
|
|
|
>;
|
|
|
|
|
|
2021-10-13 00:07:47 +02:00
|
|
|
fn finalize_after_unblind<
|
|
|
|
|
'a,
|
|
|
|
|
G: Group,
|
2021-12-23 21:58:00 +01:00
|
|
|
H: BlockSizeUser + Digest + FixedOutputReset,
|
2021-12-23 21:03:38 +01:00
|
|
|
I: AsRef<[u8]>,
|
2022-01-18 12:34:28 +01:00
|
|
|
IE: 'a + Iterator<Item = (I, G::Elem)>,
|
2021-10-13 00:07:47 +02:00
|
|
|
>(
|
2021-12-23 21:03:38 +01:00
|
|
|
inputs_and_unblinded_elements: IE,
|
|
|
|
|
info: &'a [u8],
|
2021-09-13 16:02:09 -07:00
|
|
|
mode: Mode,
|
2021-12-25 22:54:27 +01:00
|
|
|
) -> Result<FinalizeAfterUnblindResult<G, H, I, IE>> {
|
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
|
|
|
|
|
let finalize_dst = GenericArray::from(STR_FINALIZE).concat(get_context_string::<G>(mode));
|
2021-10-13 00:07:47 +02:00
|
|
|
|
2021-12-23 21:03:38 +01:00
|
|
|
Ok(inputs_and_unblinded_elements
|
|
|
|
|
// 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-18 12:34:28 +01:00
|
|
|
let finalize_dst_len = i2osp_2_array(finalize_dst);
|
|
|
|
|
let elem_len = G::ElemLen::U16.to_be_bytes();
|
|
|
|
|
|
|
|
|
|
// hashInput = I2OSP(len(input), 2) || input ||
|
|
|
|
|
// I2OSP(len(info), 2) || info ||
|
|
|
|
|
// I2OSP(len(unblindedElement), 2) || unblindedElement ||
|
|
|
|
|
// I2OSP(len(finalizeDST), 2) || finalizeDST
|
|
|
|
|
// return Hash(hashInput)
|
|
|
|
|
Ok(H::new()
|
|
|
|
|
.chain_update(i2osp_2(input.as_ref().len())?)
|
|
|
|
|
.chain_update(input.as_ref())
|
|
|
|
|
.chain_update(i2osp_2(info.len())?)
|
|
|
|
|
.chain_update(info)
|
|
|
|
|
.chain_update(elem_len)
|
|
|
|
|
.chain_update(G::serialize_elem(unblinded_element))
|
|
|
|
|
.chain_update(finalize_dst_len)
|
|
|
|
|
.chain_update(finalize_dst)
|
2021-10-16 01:56:21 +02:00
|
|
|
.finalize())
|
2021-12-23 21:03:38 +01:00
|
|
|
}))
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn compute_composites<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
2021-12-21 20:17:02 +01:00
|
|
|
k_option: Option<G::Scalar>,
|
2022-01-18 12:34:28 +01:00
|
|
|
b: G::Elem,
|
2021-10-13 00:07:47 +02:00
|
|
|
c_slice: impl Iterator<Item = EvaluationElement<G, H>> + ExactSizeIterator,
|
|
|
|
|
d_slice: impl Iterator<Item = BlindedElement<G, H>> + ExactSizeIterator,
|
2022-01-18 12:34:28 +01:00
|
|
|
) -> Result<(G::Elem, G::Elem)> {
|
|
|
|
|
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.2.3-2
|
|
|
|
|
|
|
|
|
|
let elem_len = G::ElemLen::U16.to_be_bytes();
|
|
|
|
|
|
2021-09-13 16:02:09 -07:00
|
|
|
if c_slice.len() != d_slice.len() {
|
2021-12-25 22:54:27 +01:00
|
|
|
return Err(Error::MismatchedLengthsForCompositeInputs);
|
2021-09-13 16:02:09 -07:00
|
|
|
}
|
|
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
let len = u16::try_from(c_slice.len()).map_err(|_| Error::SerializationError)?;
|
|
|
|
|
|
|
|
|
|
let seed_dst = GenericArray::from(STR_SEED).concat(get_context_string::<G>(Mode::Verifiable));
|
2021-10-13 00:07:47 +02:00
|
|
|
let composite_dst =
|
2022-01-18 12:34:28 +01:00
|
|
|
GenericArray::from(STR_COMPOSITE).concat(get_context_string::<G>(Mode::Verifiable));
|
|
|
|
|
let composite_dst_len = i2osp_2_array(composite_dst);
|
|
|
|
|
|
|
|
|
|
let seed = H::new()
|
|
|
|
|
.chain_update(&elem_len)
|
|
|
|
|
.chain_update(G::serialize_elem(b))
|
|
|
|
|
.chain_update(i2osp_2_array(seed_dst))
|
|
|
|
|
.chain_update(seed_dst)
|
2021-10-16 01:56:21 +02:00
|
|
|
.finalize();
|
2022-01-18 12:34:28 +01:00
|
|
|
let seed_len = i2osp_2(seed.len())?;
|
|
|
|
|
|
|
|
|
|
let mut m = G::identity_elem();
|
|
|
|
|
let mut z = G::identity_elem();
|
|
|
|
|
|
|
|
|
|
for (i, (c, d)) in (0..len).zip(c_slice.zip(d_slice)) {
|
|
|
|
|
// Ci = GG.SerializeElement(Cs[i])
|
|
|
|
|
let ci = G::serialize_elem(c.value);
|
|
|
|
|
// Di = GG.SerializeElement(Ds[i])
|
|
|
|
|
let di = G::serialize_elem(d.value);
|
|
|
|
|
// 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 = [
|
|
|
|
|
&seed_len,
|
|
|
|
|
seed.as_slice(),
|
|
|
|
|
&i.to_be_bytes(),
|
|
|
|
|
&elem_len,
|
|
|
|
|
&ci,
|
|
|
|
|
&elem_len,
|
|
|
|
|
&di,
|
|
|
|
|
&composite_dst_len,
|
|
|
|
|
&composite_dst,
|
|
|
|
|
];
|
|
|
|
|
let di = G::hash_to_scalar::<H>(&h2_input, Mode::Verifiable)?;
|
2021-10-13 00:07:47 +02:00
|
|
|
m = c.value * &di + &m;
|
2021-09-13 16:02:09 -07:00
|
|
|
z = match k_option {
|
|
|
|
|
Some(_) => z,
|
2021-10-13 00:07:47 +02:00
|
|
|
None => d.value * &di + &z,
|
2021-09-13 16:02:09 -07:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
2021-10-25 22:06:42 -07:00
|
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html>
|
2022-01-18 12:34:28 +01:00
|
|
|
pub(crate) fn get_context_string<G: Group>(mode: Mode) -> GenericArray<u8, U11> {
|
|
|
|
|
GenericArray::from(STR_VOPRF)
|
|
|
|
|
.concat([mode.to_u8()].into())
|
|
|
|
|
.concat(G::SUITE_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
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn prf<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
2021-09-13 16:02:09 -07:00
|
|
|
input: &[u8],
|
2021-12-21 20:17:02 +01:00
|
|
|
key: G::Scalar,
|
2021-09-13 16:02:09 -07:00
|
|
|
info: &[u8],
|
2021-09-29 17:02:40 -07:00
|
|
|
mode: Mode,
|
2022-01-04 00:45:05 +01:00
|
|
|
) -> Output<H> {
|
2022-01-18 12:34:28 +01:00
|
|
|
let point = G::hash_to_curve::<H>(&[input], mode).unwrap();
|
|
|
|
|
|
|
|
|
|
let context_string = get_context_string::<G>(mode);
|
|
|
|
|
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-18 12:34:28 +01:00
|
|
|
let m = G::hash_to_scalar::<H>(&context, mode).unwrap();
|
2021-09-13 16:02:09 -07:00
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
let res = point * &G::invert_scalar(key + &m);
|
2021-09-13 16:02:09 -07:00
|
|
|
|
2021-12-23 21:03:38 +01:00
|
|
|
finalize_after_unblind::<G, H, _, _>(Some((input, res)).into_iter(), info, mode)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.next()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.unwrap()
|
2021-09-09 01:56:54 -07:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn base_retrieval<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
2021-09-29 17:02:40 -07:00
|
|
|
let input = b"input";
|
2021-09-13 16:02:09 -07:00
|
|
|
let info = b"info";
|
2021-09-09 01:56:54 -07:00
|
|
|
let mut rng = OsRng;
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = NonVerifiableClient::<G, H>::blind(input, &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
|
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
|
2021-12-23 21:03:38 +01:00
|
|
|
.finalize(input, &server_result.message, Some(info))
|
2021-09-20 00:17:53 -07:00
|
|
|
.unwrap();
|
2021-10-13 00:07:47 +02:00
|
|
|
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-09-29 17:02:40 -07:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn verifiable_retrieval<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
2021-09-29 17:02:40 -07:00
|
|
|
let input = b"input";
|
|
|
|
|
let info = b"info";
|
|
|
|
|
let mut rng = OsRng;
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = VerifiableClient::<G, H>::blind(input, &mut rng).unwrap();
|
2021-10-06 00:53:18 +02:00
|
|
|
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
|
2021-09-29 17:02:40 -07:00
|
|
|
let server_result = server
|
2021-12-21 20:17:02 +01:00
|
|
|
.evaluate(&mut rng, &client_blind_result.message, Some(info))
|
2021-09-29 17:02:40 -07:00
|
|
|
.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,
|
2021-09-29 17:02:40 -07:00
|
|
|
server.get_public_key(),
|
2021-10-13 00:07:47 +02:00
|
|
|
Some(info),
|
2021-09-29 17:02:40 -07:00
|
|
|
)
|
|
|
|
|
.unwrap();
|
2021-10-13 00:07:47 +02:00
|
|
|
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-12-23 21:58:00 +01:00
|
|
|
fn verifiable_bad_public_key<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
2021-09-29 17:02:40 -07:00
|
|
|
let input = b"input";
|
|
|
|
|
let info = b"info";
|
|
|
|
|
let mut rng = OsRng;
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = VerifiableClient::<G, H>::blind(input, &mut rng).unwrap();
|
2021-10-06 00:53:18 +02:00
|
|
|
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
|
2021-09-29 17:02:40 -07:00
|
|
|
let server_result = server
|
2021-12-21 20:17:02 +01:00
|
|
|
.evaluate(&mut rng, &client_blind_result.message, Some(info))
|
2021-09-29 17:02:40 -07:00
|
|
|
.unwrap();
|
|
|
|
|
let wrong_pk = {
|
|
|
|
|
// Choose a group element that is unlikely to be the right public key
|
2022-01-18 12:34:28 +01:00
|
|
|
G::hash_to_curve::<H>(&[b"msg"], Mode::Base).unwrap()
|
2021-09-29 17:02:40 -07:00
|
|
|
};
|
|
|
|
|
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,
|
2021-09-29 17:02:40 -07:00
|
|
|
wrong_pk,
|
2021-10-13 00:07:47 +02:00
|
|
|
Some(info),
|
2021-09-29 17:02:40 -07:00
|
|
|
);
|
|
|
|
|
assert!(client_finalize_result.is_err());
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn verifiable_batch_retrieval<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
2021-09-29 17:02:40 -07:00
|
|
|
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];
|
2021-09-29 17:02:40 -07:00
|
|
|
rng.fill_bytes(&mut input);
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = VerifiableClient::<G, H>::blind(&input, &mut rng).unwrap();
|
2021-09-29 17:02:40 -07:00
|
|
|
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();
|
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,
|
|
|
|
|
)
|
2021-09-29 17:02:40 -07:00
|
|
|
.unwrap();
|
2021-12-29 09:14:28 +01:00
|
|
|
let messages: Vec<_> = messages.collect();
|
2021-09-29 17:02:40 -07:00
|
|
|
let client_finalize_result = VerifiableClient::batch_finalize(
|
2021-12-23 21:03:38 +01:00
|
|
|
&inputs,
|
2021-10-13 00:07:47 +02:00
|
|
|
&client_states,
|
2021-12-29 09:14:28 +01:00
|
|
|
&messages,
|
|
|
|
|
&proof,
|
2021-09-29 17:02:40 -07:00
|
|
|
server.get_public_key(),
|
2021-10-13 00:07:47 +02:00
|
|
|
Some(info),
|
2021-09-29 17:02:40 -07:00
|
|
|
)
|
2021-12-23 21:03:38 +01:00
|
|
|
.unwrap()
|
2021-12-25 22:54:27 +01:00
|
|
|
.collect::<Result<Vec<_>>>()
|
2021-09-29 17:02:40 -07:00
|
|
|
.unwrap();
|
|
|
|
|
let mut res2 = vec![];
|
2021-10-06 00:19:20 +02:00
|
|
|
for input in inputs.iter().take(num_iterations) {
|
2021-10-13 00:07:47 +02:00
|
|
|
let output = prf::<G, H>(input, server.get_private_key(), info, Mode::Verifiable);
|
2021-09-29 17:02:40 -07:00
|
|
|
res2.push(output);
|
|
|
|
|
}
|
2021-10-06 00:53:18 +02:00
|
|
|
assert_eq!(client_finalize_result, res2);
|
2021-09-29 17:02:40 -07:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn verifiable_batch_bad_public_key<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
2021-09-29 17:02:40 -07:00
|
|
|
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];
|
2021-09-29 17:02:40 -07:00
|
|
|
rng.fill_bytes(&mut input);
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = VerifiableClient::<G, H>::blind(&input, &mut rng).unwrap();
|
2021-09-29 17:02:40 -07:00
|
|
|
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();
|
2021-12-29 09:14:28 +01:00
|
|
|
let VerifiableServerBatchEvaluatePrepareResult {
|
|
|
|
|
prepared_evaluation_elements,
|
|
|
|
|
t,
|
|
|
|
|
} = server
|
|
|
|
|
.batch_evaluate_prepare(client_messages.iter(), Some(info))
|
2021-09-29 17:02:40 -07:00
|
|
|
.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();
|
2021-09-29 17:02:40 -07:00
|
|
|
let wrong_pk = {
|
|
|
|
|
// Choose a group element that is unlikely to be the right public key
|
2022-01-18 12:34:28 +01:00
|
|
|
G::hash_to_curve::<H>(&[b"msg"], Mode::Base).unwrap()
|
2021-09-29 17:02:40 -07:00
|
|
|
};
|
|
|
|
|
let client_finalize_result = VerifiableClient::batch_finalize(
|
2021-12-23 21:03:38 +01:00
|
|
|
&inputs,
|
2021-10-13 00:07:47 +02:00
|
|
|
&client_states,
|
2021-12-29 09:14:28 +01:00
|
|
|
&messages,
|
|
|
|
|
&proof,
|
2021-09-29 17:02:40 -07:00
|
|
|
wrong_pk,
|
2021-10-13 00:07:47 +02:00
|
|
|
Some(info),
|
2021-09-29 17:02:40 -07:00
|
|
|
);
|
|
|
|
|
assert!(client_finalize_result.is_err());
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn base_inversion_unsalted<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
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);
|
2021-09-13 16:02:09 -07:00
|
|
|
let info = b"info";
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = NonVerifiableClient::<G, H>::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,
|
2021-12-21 20:17:02 +01:00
|
|
|
&EvaluationElement {
|
2021-09-28 19:44:57 -07:00
|
|
|
value: client_blind_result.message.value,
|
2021-10-06 00:53:18 +02:00
|
|
|
hash: PhantomData,
|
2021-09-28 19:44:57 -07:00
|
|
|
},
|
2021-10-13 00:07:47 +02:00
|
|
|
Some(info),
|
2021-09-20 00:17:53 -07:00
|
|
|
)
|
|
|
|
|
.unwrap();
|
2021-09-09 01:56:54 -07:00
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
let point = G::hash_to_curve::<H>(&[&input], Mode::Base).unwrap();
|
2021-12-23 21:03:38 +01:00
|
|
|
let res2 = finalize_after_unblind::<G, H, _, _>(
|
|
|
|
|
Some((input.as_ref(), point)).into_iter(),
|
2021-10-13 00:07:47 +02:00
|
|
|
info,
|
|
|
|
|
Mode::Base,
|
|
|
|
|
)
|
2021-12-23 21:03:38 +01:00
|
|
|
.unwrap()
|
|
|
|
|
.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
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn zeroize_base_client<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
2021-10-11 02:51:12 +02:00
|
|
|
let input = b"input";
|
|
|
|
|
let mut rng = OsRng;
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = NonVerifiableClient::<G, H>::blind(input, &mut rng).unwrap();
|
2021-10-11 02:51:12 +02:00
|
|
|
|
|
|
|
|
let mut state = client_blind_result.state;
|
|
|
|
|
Zeroize::zeroize(&mut state);
|
2021-10-14 13:55:43 -07:00
|
|
|
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);
|
2021-10-14 13:55:43 -07:00
|
|
|
assert!(message.serialize().iter().all(|&x| x == 0));
|
2021-10-11 02:51:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn zeroize_verifiable_client<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>()
|
2021-12-23 21:03:38 +01:00
|
|
|
where
|
|
|
|
|
G::ScalarLen: Add<G::ElemLen>,
|
|
|
|
|
Sum<G::ScalarLen, G::ElemLen>: ArrayLength<u8>,
|
|
|
|
|
{
|
2021-10-11 02:51:12 +02:00
|
|
|
let input = b"input";
|
|
|
|
|
let mut rng = OsRng;
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = VerifiableClient::<G, H>::blind(input, &mut rng).unwrap();
|
2021-10-11 02:51:12 +02:00
|
|
|
|
|
|
|
|
let mut state = client_blind_result.state;
|
|
|
|
|
Zeroize::zeroize(&mut state);
|
2021-10-14 13:55:43 -07:00
|
|
|
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);
|
2021-10-14 13:55:43 -07:00
|
|
|
assert!(message.serialize().iter().all(|&x| x == 0));
|
2021-10-11 02:51:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn zeroize_base_server<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
2021-10-11 02:51:12 +02:00
|
|
|
let input = b"input";
|
|
|
|
|
let info = b"info";
|
|
|
|
|
let mut rng = OsRng;
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = NonVerifiableClient::<G, H>::blind(input, &mut rng).unwrap();
|
2021-10-11 02:51:12 +02:00
|
|
|
let server = NonVerifiableServer::<G, H>::new(&mut rng).unwrap();
|
|
|
|
|
let server_result = 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);
|
2021-10-14 13:55:43 -07:00
|
|
|
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);
|
2021-10-14 13:55:43 -07:00
|
|
|
assert!(message.serialize().iter().all(|&x| x == 0));
|
2021-10-11 02:51:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-23 21:58:00 +01:00
|
|
|
fn zeroize_verifiable_server<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>()
|
2021-12-23 21:03:38 +01:00
|
|
|
where
|
|
|
|
|
G::ScalarLen: Add<G::ElemLen>,
|
|
|
|
|
Sum<G::ScalarLen, G::ElemLen>: ArrayLength<u8>,
|
|
|
|
|
G::ScalarLen: Add<G::ScalarLen>,
|
|
|
|
|
Sum<G::ScalarLen, G::ScalarLen>: ArrayLength<u8>,
|
|
|
|
|
{
|
2021-10-11 02:51:12 +02:00
|
|
|
let input = b"input";
|
|
|
|
|
let info = b"info";
|
|
|
|
|
let mut rng = OsRng;
|
2021-12-23 21:03:38 +01:00
|
|
|
let client_blind_result = VerifiableClient::<G, H>::blind(input, &mut rng).unwrap();
|
2021-10-11 02:51:12 +02:00
|
|
|
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
|
|
|
|
|
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);
|
2021-10-14 13:55:43 -07:00
|
|
|
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);
|
2021-10-14 13:55:43 -07:00
|
|
|
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);
|
2021-10-14 13:55:43 -07:00
|
|
|
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<()> {
|
2021-12-23 07:50:48 +01:00
|
|
|
#[cfg(feature = "ristretto255")]
|
|
|
|
|
{
|
2021-12-21 20:17:02 +01:00
|
|
|
use sha2::Sha512;
|
|
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
use crate::Ristretto255;
|
|
|
|
|
|
|
|
|
|
base_retrieval::<Ristretto255, Sha512>();
|
|
|
|
|
base_inversion_unsalted::<Ristretto255, Sha512>();
|
|
|
|
|
verifiable_retrieval::<Ristretto255, Sha512>();
|
|
|
|
|
verifiable_batch_retrieval::<Ristretto255, Sha512>();
|
|
|
|
|
verifiable_bad_public_key::<Ristretto255, Sha512>();
|
|
|
|
|
verifiable_batch_bad_public_key::<Ristretto255, Sha512>();
|
|
|
|
|
|
|
|
|
|
zeroize_base_client::<Ristretto255, Sha512>();
|
|
|
|
|
zeroize_base_server::<Ristretto255, Sha512>();
|
|
|
|
|
zeroize_verifiable_client::<Ristretto255, Sha512>();
|
|
|
|
|
zeroize_verifiable_server::<Ristretto255, Sha512>();
|
2021-12-23 07:50:48 +01:00
|
|
|
}
|
2021-10-11 02:51:12 +02:00
|
|
|
|
2021-09-28 19:44:57 -07:00
|
|
|
#[cfg(feature = "p256")]
|
|
|
|
|
{
|
2022-01-18 12:34:28 +01:00
|
|
|
use p256_::NistP256;
|
2021-10-06 00:53:18 +02:00
|
|
|
use sha2::Sha256;
|
|
|
|
|
|
2022-01-18 12:34:28 +01:00
|
|
|
base_retrieval::<NistP256, Sha256>();
|
|
|
|
|
base_inversion_unsalted::<NistP256, Sha256>();
|
|
|
|
|
verifiable_retrieval::<NistP256, Sha256>();
|
|
|
|
|
verifiable_batch_retrieval::<NistP256, Sha256>();
|
|
|
|
|
verifiable_bad_public_key::<NistP256, Sha256>();
|
|
|
|
|
verifiable_batch_bad_public_key::<NistP256, Sha256>();
|
|
|
|
|
|
|
|
|
|
zeroize_base_client::<NistP256, Sha256>();
|
|
|
|
|
zeroize_base_server::<NistP256, Sha256>();
|
|
|
|
|
zeroize_verifiable_client::<NistP256, Sha256>();
|
|
|
|
|
zeroize_verifiable_server::<NistP256, Sha256>();
|
2021-09-28 19:44:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2021-09-09 01:56:54 -07:00
|
|
|
}
|