Updating to draft 11 (#80)
* draft-11 * Fix CI complaints * Address review comments, CHANGELOG entry, minor fixes
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.4.0-pre.4 (July 9, 2022)
|
||||||
|
* Updated to be in sync with draft-irtf-cfrg-voprf-11
|
||||||
|
* Adds the evaluate() function to the servers to calculate the output of the OPRF
|
||||||
|
directly
|
||||||
|
* Renames the former evaluate() function to blind_evaluate to match the spec
|
||||||
|
* Fixes the order of parameters for PoprfClient::blind to align it with the
|
||||||
|
other clients
|
||||||
|
|
||||||
## 0.4.0-pre.3 (July 1, 2022)
|
## 0.4.0-pre.3 (July 1, 2022)
|
||||||
* Updated to be in sync with draft-irtf-cfrg-voprf-10, with
|
* Updated to be in sync with draft-irtf-cfrg-voprf-10, with
|
||||||
the only difference from -09 being a constant string change
|
the only difference from -09 being a constant string change
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ name = "voprf"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/novifinancial/voprf/"
|
repository = "https://github.com/novifinancial/voprf/"
|
||||||
rust-version = "1.57"
|
rust-version = "1.57"
|
||||||
version = "0.4.0-pre.3"
|
version = "0.4.0-pre.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
alloc = []
|
alloc = []
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Installation
|
|||||||
Add the following line to the dependencies of your `Cargo.toml`:
|
Add the following line to the dependencies of your `Cargo.toml`:
|
||||||
|
|
||||||
```
|
```
|
||||||
voprf = "0.4.0-pre.3"
|
voprf = "0.4.0-pre.4"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Minimum Supported Rust Version
|
### Minimum Supported Rust Version
|
||||||
|
|||||||
+56
-7
@@ -11,7 +11,7 @@ use core::convert::TryFrom;
|
|||||||
|
|
||||||
use derive_where::derive_where;
|
use derive_where::derive_where;
|
||||||
use digest::core_api::BlockSizeUser;
|
use digest::core_api::BlockSizeUser;
|
||||||
use digest::{Digest, OutputSizeUser};
|
use digest::{Digest, Output, OutputSizeUser};
|
||||||
use generic_array::sequence::Concat;
|
use generic_array::sequence::Concat;
|
||||||
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U11, U2, U256};
|
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U11, U2, U256};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
@@ -153,7 +153,7 @@ where
|
|||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
{
|
{
|
||||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-10.html#section-2.2.1
|
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-11.html#section-2.2.1
|
||||||
|
|
||||||
let (m, z) = compute_composites::<CS, _, _>(Some(k), b, cs, ds, mode)?;
|
let (m, z) = compute_composites::<CS, _, _>(Some(k), b, cs, ds, mode)?;
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ where
|
|||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
{
|
{
|
||||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-10.html#section-2.2.2
|
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-11.html#section-2.2.2
|
||||||
let (m, z) = compute_composites::<CS, _, _>(None, b, cs, ds, mode)?;
|
let (m, z) = compute_composites::<CS, _, _>(None, b, cs, ds, mode)?;
|
||||||
let t2 = (a * &proof.s_scalar) + &(b * &proof.c_scalar);
|
let t2 = (a * &proof.s_scalar) + &(b * &proof.c_scalar);
|
||||||
let t3 = (m * &proof.s_scalar) + &(z * &proof.c_scalar);
|
let t3 = (m * &proof.s_scalar) + &(z * &proof.c_scalar);
|
||||||
@@ -285,7 +285,7 @@ where
|
|||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
{
|
{
|
||||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-10.html#section-2.2.1
|
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-11.html#section-2.2.1
|
||||||
|
|
||||||
let elem_len = <CS::Group as Group>::ElemLen::U16.to_be_bytes();
|
let elem_len = <CS::Group as Group>::ElemLen::U16.to_be_bytes();
|
||||||
|
|
||||||
@@ -437,12 +437,61 @@ where
|
|||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
{
|
{
|
||||||
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode));
|
let hashed_point = hash_to_group::<CS>(input, mode)?;
|
||||||
let hashed_point =
|
|
||||||
CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).map_err(|_| Error::Input)?;
|
|
||||||
Ok(hashed_point * blind)
|
Ok(hashed_point * blind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hashes `input` to a point on the curve
|
||||||
|
pub(crate) fn hash_to_group<CS: CipherSuite>(
|
||||||
|
input: &[u8],
|
||||||
|
mode: Mode,
|
||||||
|
) -> Result<<CS::Group as Group>::Elem>
|
||||||
|
where
|
||||||
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
|
{
|
||||||
|
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode));
|
||||||
|
CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).map_err(|_| Error::Input)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal function that finalizes the hash input for OPRF, VOPRF & POPRF.
|
||||||
|
/// Returned values can only fail with [`Error::Input`].
|
||||||
|
pub(crate) fn server_evaluate_hash_input<CS: CipherSuite>(
|
||||||
|
input: &[u8],
|
||||||
|
info: Option<&[u8]>,
|
||||||
|
issued_element: GenericArray<u8, <<CS as CipherSuite>::Group as Group>::ElemLen>,
|
||||||
|
) -> Result<Output<CS::Hash>>
|
||||||
|
where
|
||||||
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
|
{
|
||||||
|
// OPRF & VOPRF
|
||||||
|
// hashInput = I2OSP(len(input), 2) || input ||
|
||||||
|
// I2OSP(len(issuedElement), 2) || issuedElement ||
|
||||||
|
// "Finalize"
|
||||||
|
// return Hash(hashInput)
|
||||||
|
//
|
||||||
|
// POPRF
|
||||||
|
// hashInput = I2OSP(len(input), 2) || input ||
|
||||||
|
// I2OSP(len(info), 2) || info ||
|
||||||
|
// I2OSP(len(issuedElement), 2) || issuedElement ||
|
||||||
|
// "Finalize"
|
||||||
|
|
||||||
|
let mut hash = CS::Hash::new()
|
||||||
|
.chain_update(i2osp_2(input.as_ref().len()).map_err(|_| Error::Input)?)
|
||||||
|
.chain_update(input.as_ref());
|
||||||
|
if let Some(info) = info {
|
||||||
|
hash = hash
|
||||||
|
.chain_update(i2osp_2(info.as_ref().len()).map_err(|_| Error::Input)?)
|
||||||
|
.chain_update(info.as_ref());
|
||||||
|
}
|
||||||
|
Ok(hash
|
||||||
|
.chain_update(i2osp_2(issued_element.as_ref().len()).map_err(|_| Error::Input)?)
|
||||||
|
.chain_update(issued_element)
|
||||||
|
.chain_update(STR_FINALIZE)
|
||||||
|
.finalize())
|
||||||
|
}
|
||||||
|
|
||||||
/// Generates the contextString parameter as defined in
|
/// Generates the contextString parameter as defined in
|
||||||
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
|
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
|
||||||
pub(crate) fn create_context_string<CS: CipherSuite>(mode: Mode) -> GenericArray<u8, U11>
|
pub(crate) fn create_context_string<CS: CipherSuite>(mode: Mode) -> GenericArray<u8, U11>
|
||||||
|
|||||||
+136
-54
@@ -8,7 +8,7 @@
|
|||||||
//! An implementation of a verifiable oblivious pseudorandom function (VOPRF)
|
//! An implementation of a verifiable oblivious pseudorandom function (VOPRF)
|
||||||
//!
|
//!
|
||||||
//! Note: This implementation is in sync with
|
//! Note: This implementation is in sync with
|
||||||
//! [draft-irtf-cfrg-voprf-10](https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-10.html),
|
//! [draft-irtf-cfrg-voprf-11](https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-11.html),
|
||||||
//! but this specification is subject to change, until the final version
|
//! but this specification is subject to change, until the final version
|
||||||
//! published by the IETF.
|
//! published by the IETF.
|
||||||
//!
|
//!
|
||||||
@@ -36,18 +36,19 @@
|
|||||||
//! VOPRF, where a public input can be supplied to the PRF computation
|
//! VOPRF, where a public input can be supplied to the PRF computation
|
||||||
//!
|
//!
|
||||||
//! In all of these modes, the protocol begins with a client blinding, followed
|
//! In all of these modes, the protocol begins with a client blinding, followed
|
||||||
//! by a server evaluation, and finishes with a client finalization.
|
//! by a server evaluation, and finishes with a client finalization and server
|
||||||
|
//! evaluation.
|
||||||
//!
|
//!
|
||||||
//! ## Base Mode
|
//! ## Base Mode
|
||||||
//!
|
//!
|
||||||
//! In base mode, an [OprfClient] interacts with an [OprfServer]
|
//! In base mode, an [OprfClient] interacts with an [OprfServer] to compute the
|
||||||
//! to compute the output of the OPRF.
|
//! output of the OPRF.
|
||||||
//!
|
//!
|
||||||
//! ### Server Setup
|
//! ### Server Setup
|
||||||
//!
|
//!
|
||||||
//! The protocol begins with a setup phase, in which the server must run
|
//! The protocol begins with a setup phase, in which the server must run
|
||||||
//! [OprfServer::new()] to produce an instance of itself. This instance
|
//! [OprfServer::new()] to produce an instance of itself. This instance must be
|
||||||
//! must be persisted on the server and used for online client evaluations.
|
//! persisted on the server and used for online client evaluations.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
@@ -64,11 +65,10 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Client Blinding
|
//! ### Client Blinding
|
||||||
//!
|
//!
|
||||||
//! In the first step, the client chooses an input, and runs
|
//! In the first step, the client chooses an input, and runs [OprfClient::blind]
|
||||||
//! [OprfClient::blind] to produce an [OprfClientBlindResult],
|
//! to produce an [OprfClientBlindResult], which consists of a [BlindedElement]
|
||||||
//! which consists of a [BlindedElement] to be sent to the server and an
|
//! to be sent to the server and an [OprfClient] which must be persisted on the
|
||||||
//! [OprfClient] which must be persisted on the client for the final
|
//! client for the final step of the VOPRF protocol.
|
||||||
//! step of the VOPRF protocol.
|
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
@@ -84,11 +84,11 @@
|
|||||||
//! .expect("Unable to construct client");
|
//! .expect("Unable to construct client");
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ### Server Evaluation
|
//! ### Server Blind Evaluation
|
||||||
//!
|
//!
|
||||||
//! In the second step, the server takes as input the message from
|
//! In the second step, the server takes as input the message from
|
||||||
//! [OprfClient::blind] (a [BlindedElement]), and runs
|
//! [OprfClient::blind] (a [BlindedElement]), and runs
|
||||||
//! [OprfServer::evaluate] to produce [EvaluationElement] to be sent to
|
//! [OprfServer::blind_evaluate] to produce [EvaluationElement] to be sent to
|
||||||
//! the client.
|
//! the client.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
@@ -107,13 +107,13 @@
|
|||||||
//! # use voprf::OprfServer;
|
//! # use voprf::OprfServer;
|
||||||
//! # let mut server_rng = OsRng;
|
//! # let mut server_rng = OsRng;
|
||||||
//! # let server = OprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
//! # let server = OprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
//! let server_evaluate_result = server.evaluate(&client_blind_result.message);
|
//! let server_evaluate_result = server.blind_evaluate(&client_blind_result.message);
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ### Client Finalization
|
//! ### Client Finalization
|
||||||
//!
|
//!
|
||||||
//! In the final step, the client takes as input the message from
|
//! In the final step on the client side, the client takes as input the message
|
||||||
//! [OprfServer::evaluate] (an [EvaluationElement]), and runs
|
//! from [OprfServer::evaluate] (an [EvaluationElement]), and runs
|
||||||
//! [OprfClient::finalize] to produce an output for the protocol.
|
//! [OprfClient::finalize] to produce an output for the protocol.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
//! # use voprf::OprfServer;
|
//! # use voprf::OprfServer;
|
||||||
//! # let mut server_rng = OsRng;
|
//! # let mut server_rng = OsRng;
|
||||||
//! # let server = OprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
//! # let server = OprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
//! # let message = server.evaluate(&client_blind_result.message);
|
//! # let message = server.blind_evaluate(&client_blind_result.message);
|
||||||
//! let client_finalize_result = client_blind_result
|
//! let client_finalize_result = client_blind_result
|
||||||
//! .state
|
//! .state
|
||||||
//! .finalize(b"input", &message)
|
//! .finalize(b"input", &message)
|
||||||
@@ -141,10 +141,47 @@
|
|||||||
//! println!("VOPRF output: {:?}", client_finalize_result.to_vec());
|
//! println!("VOPRF output: {:?}", client_finalize_result.to_vec());
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! ### Server Evaluation
|
||||||
|
//!
|
||||||
|
//! Optionally, if the server has direct access to the PRF input, then it need
|
||||||
|
//! not perform the oblivious computation and can simply run
|
||||||
|
//! [OprfServer::evaluate] to generate an output which matches the output
|
||||||
|
//! produced by an execution of the oblivious protocol on the same input and
|
||||||
|
//! key.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
|
//! # type CipherSuite = voprf::Ristretto255;
|
||||||
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
|
//! # type CipherSuite = p256::NistP256;
|
||||||
|
//! # use voprf::OprfClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_blind_result = OprfClient::<CipherSuite>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # use voprf::OprfServer;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server = OprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
|
//! # let message = server.blind_evaluate(&client_blind_result.message);
|
||||||
|
//! let client_finalize_result = client_blind_result
|
||||||
|
//! .state
|
||||||
|
//! .finalize(b"input", &message)
|
||||||
|
//! .expect("Unable to perform client finalization");
|
||||||
|
//!
|
||||||
|
//! let server_evaluate_result = server
|
||||||
|
//! .evaluate(b"input")
|
||||||
|
//! .expect("Unable to perform the server evaluation");
|
||||||
|
//!
|
||||||
|
//! assert_eq!(client_finalize_result, server_evaluate_result);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
//! ## Verifiable Mode
|
//! ## Verifiable Mode
|
||||||
//!
|
//!
|
||||||
//! In verifiable mode, a [VoprfClient] interacts with a [VoprfServer]
|
//! In verifiable mode, a [VoprfClient] interacts with a [VoprfServer] to
|
||||||
//! to compute the output of the VOPRF. In order to verify the server's
|
//! compute the output of the VOPRF. In order to verify the server's
|
||||||
//! computation, the client checks a server-generated proof against the server's
|
//! computation, the client checks a server-generated proof against the server's
|
||||||
//! public key. If the proof fails to verify, then the client does not receive
|
//! public key. If the proof fails to verify, then the client does not receive
|
||||||
//! an output.
|
//! an output.
|
||||||
@@ -156,8 +193,8 @@
|
|||||||
//! ### Server Setup
|
//! ### Server Setup
|
||||||
//!
|
//!
|
||||||
//! The protocol begins with a setup phase, in which the server must run
|
//! The protocol begins with a setup phase, in which the server must run
|
||||||
//! [VoprfServer::new()] to produce an instance of itself. This instance
|
//! [VoprfServer::new()] to produce an instance of itself. This instance must be
|
||||||
//! must be persisted on the server and used for online client evaluations.
|
//! persisted on the server and used for online client evaluations.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
@@ -182,10 +219,9 @@
|
|||||||
//! ### Client Blinding
|
//! ### Client Blinding
|
||||||
//!
|
//!
|
||||||
//! In the first step, the client chooses an input, and runs
|
//! In the first step, the client chooses an input, and runs
|
||||||
//! [VoprfClient::blind] to produce a [VoprfClientBlindResult], which
|
//! [VoprfClient::blind] to produce a [VoprfClientBlindResult], which consists
|
||||||
//! consists of a [BlindedElement] to be sent to the server and a
|
//! of a [BlindedElement] to be sent to the server and a [VoprfClient] which
|
||||||
//! [VoprfClient] which must be persisted on the client for the final step
|
//! must be persisted on the client for the final step of the VOPRF protocol.
|
||||||
//! of the VOPRF protocol.
|
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
@@ -201,11 +237,11 @@
|
|||||||
//! .expect("Unable to construct client");
|
//! .expect("Unable to construct client");
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ### Server Evaluation
|
//! ### Server Blind Evaluation
|
||||||
//!
|
//!
|
||||||
//! In the second step, the server takes as input the message from
|
//! In the second step, the server takes as input the message from
|
||||||
//! [VoprfClient::blind] (a [BlindedElement]), and runs
|
//! [VoprfClient::blind] (a [BlindedElement]), and runs
|
||||||
//! [VoprfServer::evaluate] to produce a [VoprfServerEvaluateResult],
|
//! [VoprfServer::blind_evaluate] to produce a [VoprfServerEvaluateResult],
|
||||||
//! which consists of an [EvaluationElement] to be sent to the client along with
|
//! which consists of an [EvaluationElement] to be sent to the client along with
|
||||||
//! a proof.
|
//! a proof.
|
||||||
//!
|
//!
|
||||||
@@ -226,15 +262,15 @@
|
|||||||
//! # let mut server_rng = OsRng;
|
//! # let mut server_rng = OsRng;
|
||||||
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
//! let VoprfServerEvaluateResult { message, proof } =
|
//! let VoprfServerEvaluateResult { message, proof } =
|
||||||
//! server.evaluate(&mut server_rng, &client_blind_result.message);
|
//! server.blind_evaluate(&mut server_rng, &client_blind_result.message);
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ### Client Finalization
|
//! ### Client Finalization
|
||||||
//!
|
//!
|
||||||
//! In the final step, the client takes as input the message from
|
//! In the final step, the client takes as input the message from
|
||||||
//! [VoprfServer::evaluate] (an [EvaluationElement]), the proof, and the
|
//! [VoprfServer::blind_evaluate] (an [EvaluationElement]), the proof, and the
|
||||||
//! server's public key, and runs [VoprfClient::finalize] to produce an
|
//! server's public key, and runs [VoprfClient::finalize] to produce an output
|
||||||
//! output for the protocol.
|
//! for the protocol.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
@@ -252,7 +288,7 @@
|
|||||||
//! # use voprf::VoprfServer;
|
//! # use voprf::VoprfServer;
|
||||||
//! # let mut server_rng = OsRng;
|
//! # let mut server_rng = OsRng;
|
||||||
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
//! # let server_evaluate_result = server.evaluate(
|
//! # let server_evaluate_result = server.blind_evaluate(
|
||||||
//! # &mut server_rng,
|
//! # &mut server_rng,
|
||||||
//! # &client_blind_result.message,
|
//! # &client_blind_result.message,
|
||||||
//! # );
|
//! # );
|
||||||
@@ -269,6 +305,51 @@
|
|||||||
//! println!("VOPRF output: {:?}", client_finalize_result.to_vec());
|
//! println!("VOPRF output: {:?}", client_finalize_result.to_vec());
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! ### Server Evaluation
|
||||||
|
//!
|
||||||
|
//! Optionally, if the server has direct access to the PRF input, then it need
|
||||||
|
//! not perform the oblivious computation and can simply run
|
||||||
|
//! [VoprfServer::evaluate] to generate an output which matches the output
|
||||||
|
//! produced by an execution of the oblivious protocol on the same input and
|
||||||
|
//! key.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
|
//! # type CipherSuite = voprf::Ristretto255;
|
||||||
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
|
//! # type CipherSuite = p256::NistP256;
|
||||||
|
//! # use voprf::VoprfClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_blind_result = VoprfClient::<CipherSuite>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # use voprf::VoprfServer;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
|
//! # let server_evaluate_result = server.blind_evaluate(
|
||||||
|
//! # &mut server_rng,
|
||||||
|
//! # &client_blind_result.message,
|
||||||
|
//! # );
|
||||||
|
//! let client_finalize_result = client_blind_result
|
||||||
|
//! .state
|
||||||
|
//! .finalize(
|
||||||
|
//! b"input",
|
||||||
|
//! &server_evaluate_result.message,
|
||||||
|
//! &server_evaluate_result.proof,
|
||||||
|
//! server.get_public_key(),
|
||||||
|
//! )
|
||||||
|
//! .expect("Unable to perform client finalization");
|
||||||
|
//!
|
||||||
|
//! let server_evaluate_result = server
|
||||||
|
//! .evaluate(b"input")
|
||||||
|
//! .expect("Unable to perform the server evaluation");
|
||||||
|
//!
|
||||||
|
//! assert_eq!(client_finalize_result, server_evaluate_result);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
//! # Advanced Usage
|
//! # Advanced Usage
|
||||||
//!
|
//!
|
||||||
//! There are two additional (and optional) extensions to the core VOPRF
|
//! There are two additional (and optional) extensions to the core VOPRF
|
||||||
@@ -279,9 +360,9 @@
|
|||||||
//!
|
//!
|
||||||
//! It is sometimes desirable to generate only a single, constant-size proof for
|
//! It is sometimes desirable to generate only a single, constant-size proof for
|
||||||
//! an unbounded number of VOPRF evaluations (on arbitrary inputs).
|
//! an unbounded number of VOPRF evaluations (on arbitrary inputs).
|
||||||
//! [VoprfClient] and [VoprfServer] support a batch API for handling
|
//! [VoprfClient] and [VoprfServer] support a batch API for handling this case.
|
||||||
//! this case. In the following example, we show how to use the batch API to
|
//! In the following example, we show how to use the batch API to produce a
|
||||||
//! produce a single proof for 10 parallel VOPRF evaluations.
|
//! single proof for 10 parallel VOPRF evaluations.
|
||||||
//!
|
//!
|
||||||
//! First, the client produces 10 blindings, storing their resulting states and
|
//! First, the client produces 10 blindings, storing their resulting states and
|
||||||
//! messages:
|
//! messages:
|
||||||
@@ -305,8 +386,8 @@
|
|||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Next, the server calls the [VoprfServer::batch_evaluate_prepare] and
|
//! Next, the server calls the [VoprfServer::batch_blind_evaluate_prepare] and
|
||||||
//! [VoprfServer::batch_evaluate_finish] function on a set of client
|
//! [VoprfServer::batch_blind_evaluate_finish] function on a set of client
|
||||||
//! messages, to produce a corresponding set of messages to be returned to the
|
//! messages, to produce a corresponding set of messages to be returned to the
|
||||||
//! client (returned in the same order), along with a single proof:
|
//! client (returned in the same order), along with a single proof:
|
||||||
//!
|
//!
|
||||||
@@ -332,15 +413,15 @@
|
|||||||
//! # use voprf::VoprfServer;
|
//! # use voprf::VoprfServer;
|
||||||
//! let mut server_rng = OsRng;
|
//! let mut server_rng = OsRng;
|
||||||
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
//! let prepared_evaluation_elements = server.batch_evaluate_prepare(client_messages.iter());
|
//! let prepared_evaluation_elements = server.batch_blind_evaluate_prepare(client_messages.iter());
|
||||||
//! let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
|
//! let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
|
||||||
//! let VoprfServerBatchEvaluateFinishResult { messages, proof } = server
|
//! let VoprfServerBatchEvaluateFinishResult { messages, proof } = server
|
||||||
//! .batch_evaluate_finish(&mut server_rng, client_messages.iter(), &prepared_elements)
|
//! .batch_blind_evaluate_finish(&mut server_rng, client_messages.iter(), &prepared_elements)
|
||||||
//! .expect("Unable to perform server batch evaluate");
|
//! .expect("Unable to perform server batch evaluate");
|
||||||
//! let messages: Vec<_> = messages.collect();
|
//! let messages: Vec<_> = messages.collect();
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! If `alloc` is available, `VoprfServer::batch_evaluate` can be called
|
//! If `alloc` is available, `VoprfServer::batch_blind_evaluate` can be called
|
||||||
//! to avoid having to collect output manually:
|
//! to avoid having to collect output manually:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
@@ -367,15 +448,15 @@
|
|||||||
//! let mut server_rng = OsRng;
|
//! let mut server_rng = OsRng;
|
||||||
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
//! let VoprfServerBatchEvaluateResult { messages, proof } = server
|
//! let VoprfServerBatchEvaluateResult { messages, proof } = server
|
||||||
//! .batch_evaluate(&mut server_rng, &client_messages)
|
//! .batch_blind_evaluate(&mut server_rng, &client_messages)
|
||||||
//! .expect("Unable to perform server batch evaluate");
|
//! .expect("Unable to perform server batch evaluate");
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Then, the client calls [VoprfClient::batch_finalize] on the client
|
//! Then, the client calls [VoprfClient::batch_finalize] on the client states
|
||||||
//! states saved from the first step, along with the messages returned by the
|
//! saved from the first step, along with the messages returned by the server,
|
||||||
//! server, along with the server's proof, in order to produce a vector of
|
//! along with the server's proof, in order to produce a vector of outputs if
|
||||||
//! outputs if the proof verifies correctly.
|
//! the proof verifies correctly.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "alloc")] {
|
//! # #[cfg(feature = "alloc")] {
|
||||||
@@ -401,7 +482,7 @@
|
|||||||
//! # let mut server_rng = OsRng;
|
//! # let mut server_rng = OsRng;
|
||||||
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
//! # let server = VoprfServer::<CipherSuite>::new(&mut server_rng).unwrap();
|
||||||
//! # let VoprfServerBatchEvaluateResult { messages, proof } = server
|
//! # let VoprfServerBatchEvaluateResult { messages, proof } = server
|
||||||
//! # .batch_evaluate(&mut server_rng, &client_messages)
|
//! # .batch_blind_evaluate(&mut server_rng, &client_messages)
|
||||||
//! # .expect("Unable to perform server batch evaluate");
|
//! # .expect("Unable to perform server batch evaluate");
|
||||||
//! let client_batch_finalize_result = VoprfClient::batch_finalize(
|
//! let client_batch_finalize_result = VoprfClient::batch_finalize(
|
||||||
//! &[b"input"; 10],
|
//! &[b"input"; 10],
|
||||||
@@ -420,17 +501,17 @@
|
|||||||
//! ## Metadata
|
//! ## Metadata
|
||||||
//!
|
//!
|
||||||
//! The optional metadata parameter included in the POPRF mode allows clients
|
//! The optional metadata parameter included in the POPRF mode allows clients
|
||||||
//! and servers to cryptographically bind additional data to the
|
//! and servers to cryptographically bind additional data to the VOPRF output.
|
||||||
//! VOPRF output. This metadata is known to both parties at the start of the
|
//! This metadata is known to both parties at the start of the protocol, and is
|
||||||
//! protocol, and is inserted under the server's evaluate step and the client's
|
//! inserted under the server's blind evaluate step and the client's finalize
|
||||||
//! finalize step. This metadata can be constructed with some type of
|
//! step. This metadata can be constructed with some type of higher-level domain
|
||||||
//! higher-level domain separation to avoid cross-protocol attacks or related
|
//! separation to avoid cross-protocol attacks or related issues.
|
||||||
//! issues.
|
|
||||||
//!
|
//!
|
||||||
//! The API for POPRF mode is similar to VOPRF mode, except that a [PoprfServer]
|
//! The API for POPRF mode is similar to VOPRF mode, except that a [PoprfServer]
|
||||||
//! and [PoprfClient] are used, and that each of the functions accept an
|
//! and [PoprfClient] are used, and that each of the functions accept an
|
||||||
//! additional (and optional) info parameter which represents the public input.
|
//! additional (and optional) info parameter which represents the public input.
|
||||||
//! See <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-10.html#name-poprf-public-input>
|
//! See
|
||||||
|
//! <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-11.html#name-poprf-public-input>
|
||||||
//! for more detailed information on how this public input should be used.
|
//! for more detailed information on how this public input should be used.
|
||||||
//!
|
//!
|
||||||
//! # Features
|
//! # Features
|
||||||
@@ -464,7 +545,8 @@
|
|||||||
//! automatically enable the `ristretto255-u64` feature and requires Rust
|
//! automatically enable the `ristretto255-u64` feature and requires Rust
|
||||||
//! nightly.
|
//! nightly.
|
||||||
//!
|
//!
|
||||||
//! [curve25519-dalek]: (https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features)
|
//! [curve25519-dalek]:
|
||||||
|
//! (https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features)
|
||||||
|
|
||||||
#![cfg_attr(not(test), deny(unsafe_code))]
|
#![cfg_attr(not(test), deny(unsafe_code))]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|||||||
+51
-5
@@ -17,8 +17,8 @@ use generic_array::GenericArray;
|
|||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
use crate::common::{
|
use crate::common::{
|
||||||
derive_key_internal, deterministic_blind_unchecked, i2osp_2, BlindedElement, EvaluationElement,
|
derive_key_internal, deterministic_blind_unchecked, hash_to_group, i2osp_2,
|
||||||
Mode, STR_FINALIZE,
|
server_evaluate_hash_input, BlindedElement, EvaluationElement, Mode, STR_FINALIZE,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use crate::serialization::serde::Scalar;
|
use crate::serialization::serde::Scalar;
|
||||||
@@ -202,9 +202,25 @@ where
|
|||||||
/// Computes the second step for the multiplicative blinding version of
|
/// Computes the second step for the multiplicative blinding version of
|
||||||
/// DH-OPRF. This message is sent from the server (who holds the OPRF key)
|
/// DH-OPRF. This message is sent from the server (who holds the OPRF key)
|
||||||
/// to the client.
|
/// to the client.
|
||||||
pub fn evaluate(&self, blinded_element: &BlindedElement<CS>) -> EvaluationElement<CS> {
|
pub fn blind_evaluate(&self, blinded_element: &BlindedElement<CS>) -> EvaluationElement<CS> {
|
||||||
EvaluationElement(blinded_element.0 * &self.sk)
|
EvaluationElement(blinded_element.0 * &self.sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the output of the OPRF on the server side
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// [`Error::Input`] if the `input` is longer then [`u16::MAX`].
|
||||||
|
pub fn evaluate(&self, input: &[u8]) -> Result<Output<<CS as CipherSuite>::Hash>> {
|
||||||
|
let input_element = hash_to_group::<CS>(input, Mode::Oprf)?;
|
||||||
|
if CS::Group::is_identity_elem(input_element).into() {
|
||||||
|
return Err(Error::Input);
|
||||||
|
};
|
||||||
|
let evaluated_element = input_element * &self.sk;
|
||||||
|
|
||||||
|
let issued_element = CS::Group::serialize_elem(evaluated_element);
|
||||||
|
|
||||||
|
server_evaluate_hash_input::<CS>(input, None, issued_element)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
@@ -312,7 +328,7 @@ mod tests {
|
|||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let client_blind_result = OprfClient::<CS>::blind(input, &mut rng).unwrap();
|
let client_blind_result = OprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
let server = OprfServer::<CS>::new(&mut rng).unwrap();
|
let server = OprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let message = server.evaluate(&client_blind_result.message);
|
let message = server.blind_evaluate(&client_blind_result.message);
|
||||||
let client_finalize_result = client_blind_result.state.finalize(input, &message).unwrap();
|
let client_finalize_result = client_blind_result.state.finalize(input, &message).unwrap();
|
||||||
let res2 = prf::<CS>(input, server.get_private_key(), &[], Mode::Oprf);
|
let res2 = prf::<CS>(input, server.get_private_key(), &[], Mode::Oprf);
|
||||||
assert_eq!(client_finalize_result, res2);
|
assert_eq!(client_finalize_result, res2);
|
||||||
@@ -343,6 +359,34 @@ mod tests {
|
|||||||
assert_eq!(client_finalize_result, res2);
|
assert_eq!(client_finalize_result, res2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn server_evaluate<CS: CipherSuite>()
|
||||||
|
where
|
||||||
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
|
{
|
||||||
|
let input = b"input";
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let client_blind_result = OprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
|
let server = OprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
|
let server_result = server.blind_evaluate(&client_blind_result.message);
|
||||||
|
|
||||||
|
let client_finalize = client_blind_result
|
||||||
|
.state
|
||||||
|
.finalize(input, &server_result)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// We expect the outputs from client and server to be equal given an identical
|
||||||
|
// input
|
||||||
|
let server_evaluate = server.evaluate(input).unwrap();
|
||||||
|
assert_eq!(client_finalize, server_evaluate);
|
||||||
|
|
||||||
|
// We expect the outputs from client and server to be different given different
|
||||||
|
// inputs
|
||||||
|
let wrong_input = b"wrong input";
|
||||||
|
let server_evaluate = server.evaluate(wrong_input).unwrap();
|
||||||
|
assert!(client_finalize != server_evaluate);
|
||||||
|
}
|
||||||
|
|
||||||
fn zeroize_oprf_client<CS: CipherSuite>()
|
fn zeroize_oprf_client<CS: CipherSuite>()
|
||||||
where
|
where
|
||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
@@ -370,7 +414,7 @@ mod tests {
|
|||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let client_blind_result = OprfClient::<CS>::blind(input, &mut rng).unwrap();
|
let client_blind_result = OprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
let server = OprfServer::<CS>::new(&mut rng).unwrap();
|
let server = OprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let mut message = server.evaluate(&client_blind_result.message);
|
let mut message = server.blind_evaluate(&client_blind_result.message);
|
||||||
|
|
||||||
let mut state = server;
|
let mut state = server;
|
||||||
unsafe { ptr::drop_in_place(&mut state) };
|
unsafe { ptr::drop_in_place(&mut state) };
|
||||||
@@ -390,6 +434,7 @@ mod tests {
|
|||||||
|
|
||||||
base_retrieval::<Ristretto255>();
|
base_retrieval::<Ristretto255>();
|
||||||
base_inversion_unsalted::<Ristretto255>();
|
base_inversion_unsalted::<Ristretto255>();
|
||||||
|
server_evaluate::<Ristretto255>();
|
||||||
|
|
||||||
zeroize_oprf_client::<Ristretto255>();
|
zeroize_oprf_client::<Ristretto255>();
|
||||||
zeroize_oprf_server::<Ristretto255>();
|
zeroize_oprf_server::<Ristretto255>();
|
||||||
@@ -397,6 +442,7 @@ mod tests {
|
|||||||
|
|
||||||
base_retrieval::<NistP256>();
|
base_retrieval::<NistP256>();
|
||||||
base_inversion_unsalted::<NistP256>();
|
base_inversion_unsalted::<NistP256>();
|
||||||
|
server_evaluate::<NistP256>();
|
||||||
|
|
||||||
zeroize_oprf_client::<NistP256>();
|
zeroize_oprf_client::<NistP256>();
|
||||||
zeroize_oprf_server::<NistP256>();
|
zeroize_oprf_server::<NistP256>();
|
||||||
|
|||||||
+86
-23
@@ -20,9 +20,10 @@ use generic_array::GenericArray;
|
|||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
use crate::common::{
|
use crate::common::{
|
||||||
create_context_string, derive_keypair, deterministic_blind_unchecked, generate_proof, i2osp_2,
|
create_context_string, derive_keypair, deterministic_blind_unchecked, generate_proof,
|
||||||
verify_proof, BlindedElement, EvaluationElement, Mode, PreparedEvaluationElement, Proof,
|
hash_to_group, i2osp_2, server_evaluate_hash_input, verify_proof, BlindedElement,
|
||||||
STR_FINALIZE, STR_HASH_TO_SCALAR, STR_INFO,
|
EvaluationElement, Mode, PreparedEvaluationElement, Proof, STR_FINALIZE, STR_HASH_TO_SCALAR,
|
||||||
|
STR_INFO,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use crate::serialization::serde::{Element, Scalar};
|
use crate::serialization::serde::{Element, Scalar};
|
||||||
@@ -89,8 +90,8 @@ where
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
/// [`Error::Input`] if the `input` is empty or longer than [`u16::MAX`].
|
/// [`Error::Input`] if the `input` is empty or longer than [`u16::MAX`].
|
||||||
pub fn blind<R: RngCore + CryptoRng>(
|
pub fn blind<R: RngCore + CryptoRng>(
|
||||||
blinding_factor_rng: &mut R,
|
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
|
blinding_factor_rng: &mut R,
|
||||||
) -> Result<PoprfClientBlindResult<CS>> {
|
) -> Result<PoprfClientBlindResult<CS>> {
|
||||||
let blind = CS::Group::random_scalar(blinding_factor_rng);
|
let blind = CS::Group::random_scalar(blinding_factor_rng);
|
||||||
Self::deterministic_blind_unchecked_inner(input, blind)
|
Self::deterministic_blind_unchecked_inner(input, blind)
|
||||||
@@ -248,7 +249,7 @@ where
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
/// - [`Error::Info`] if the `info` is longer than `u16::MAX`.
|
/// - [`Error::Info`] if the `info` is longer than `u16::MAX`.
|
||||||
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
|
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
|
||||||
pub fn evaluate<R: RngCore + CryptoRng>(
|
pub fn blind_evaluate<R: RngCore + CryptoRng>(
|
||||||
&self,
|
&self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
blinded_element: &BlindedElement<CS>,
|
blinded_element: &BlindedElement<CS>,
|
||||||
@@ -257,7 +258,7 @@ where
|
|||||||
let PoprfServerBatchEvaluatePrepareResult {
|
let PoprfServerBatchEvaluatePrepareResult {
|
||||||
mut prepared_evaluation_elements,
|
mut prepared_evaluation_elements,
|
||||||
prepared_tweak,
|
prepared_tweak,
|
||||||
} = self.batch_evaluate_prepare(iter::once(blinded_element), info)?;
|
} = self.batch_blind_evaluate_prepare(iter::once(blinded_element), info)?;
|
||||||
|
|
||||||
let prepared_evaluation_element = prepared_evaluation_elements.next().unwrap();
|
let prepared_evaluation_element = prepared_evaluation_elements.next().unwrap();
|
||||||
let prepared_evaluation_elements = core::array::from_ref(&prepared_evaluation_element);
|
let prepared_evaluation_elements = core::array::from_ref(&prepared_evaluation_element);
|
||||||
@@ -265,7 +266,7 @@ where
|
|||||||
let PoprfServerBatchEvaluateFinishResult {
|
let PoprfServerBatchEvaluateFinishResult {
|
||||||
mut messages,
|
mut messages,
|
||||||
proof,
|
proof,
|
||||||
} = Self::batch_evaluate_finish(
|
} = Self::batch_blind_evaluate_finish(
|
||||||
rng,
|
rng,
|
||||||
iter::once(blinded_element),
|
iter::once(blinded_element),
|
||||||
prepared_evaluation_elements,
|
prepared_evaluation_elements,
|
||||||
@@ -286,7 +287,7 @@ where
|
|||||||
/// - [`Error::Info`] if the `info` is longer than `u16::MAX`.
|
/// - [`Error::Info`] if the `info` is longer than `u16::MAX`.
|
||||||
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
|
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub fn batch_evaluate<'a, R: RngCore + CryptoRng, IE>(
|
pub fn batch_blind_evaluate<'a, R: RngCore + CryptoRng, IE>(
|
||||||
&self,
|
&self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
blinded_elements: &'a IE,
|
blinded_elements: &'a IE,
|
||||||
@@ -300,13 +301,13 @@ where
|
|||||||
let PoprfServerBatchEvaluatePrepareResult {
|
let PoprfServerBatchEvaluatePrepareResult {
|
||||||
prepared_evaluation_elements,
|
prepared_evaluation_elements,
|
||||||
prepared_tweak,
|
prepared_tweak,
|
||||||
} = self.batch_evaluate_prepare(blinded_elements.into_iter(), info)?;
|
} = self.batch_blind_evaluate_prepare(blinded_elements.into_iter(), info)?;
|
||||||
|
|
||||||
let prepared_evaluation_elements: Vec<_> = prepared_evaluation_elements.collect();
|
let prepared_evaluation_elements: Vec<_> = prepared_evaluation_elements.collect();
|
||||||
|
|
||||||
// This can't fail because we know the size of the inputs.
|
// This can't fail because we know the size of the inputs.
|
||||||
let PoprfServerBatchEvaluateFinishResult { messages, proof } =
|
let PoprfServerBatchEvaluateFinishResult { messages, proof } =
|
||||||
Self::batch_evaluate_finish::<_, _, Vec<_>>(
|
Self::batch_blind_evaluate_finish::<_, _, Vec<_>>(
|
||||||
rng,
|
rng,
|
||||||
blinded_elements.into_iter(),
|
blinded_elements.into_iter(),
|
||||||
&prepared_evaluation_elements,
|
&prepared_evaluation_elements,
|
||||||
@@ -319,15 +320,15 @@ where
|
|||||||
Ok(PoprfServerBatchEvaluateResult { messages, proof })
|
Ok(PoprfServerBatchEvaluateResult { messages, proof })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alternative version of `batch_evaluate` without
|
/// Alternative version of `batch_blind_evaluate` without
|
||||||
/// memory allocation. Returned [`PreparedEvaluationElement`] have to
|
/// memory allocation. Returned [`PreparedEvaluationElement`] have to
|
||||||
/// be [`collect`](Iterator::collect)ed and passed into
|
/// be [`collect`](Iterator::collect)ed and passed into
|
||||||
/// [`batch_evaluate_finish`](Self::batch_evaluate_finish).
|
/// [`batch_blind_evaluate_finish`](Self::batch_blind_evaluate_finish).
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// - [`Error::Info`] if the `info` is longer than `u16::MAX`.
|
/// - [`Error::Info`] if the `info` is longer than `u16::MAX`.
|
||||||
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
|
/// - [`Error::Protocol`] if the protocol fails and can't be completed.
|
||||||
pub fn batch_evaluate_prepare<'a, I: Iterator<Item = &'a BlindedElement<CS>>>(
|
pub fn batch_blind_evaluate_prepare<'a, I: Iterator<Item = &'a BlindedElement<CS>>>(
|
||||||
&self,
|
&self,
|
||||||
blinded_elements: I,
|
blinded_elements: I,
|
||||||
info: Option<&[u8]>,
|
info: Option<&[u8]>,
|
||||||
@@ -349,14 +350,14 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`batch_evaluate_prepare`](Self::batch_evaluate_prepare) for more
|
/// See [`batch_blind_evaluate_prepare`](Self::batch_blind_evaluate_prepare)
|
||||||
/// details.
|
/// for more details.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// [`Error::Batch`] if the number of `blinded_elements` and
|
/// [`Error::Batch`] if the number of `blinded_elements` and
|
||||||
/// `prepared_evaluation_elements` don't match or is longer then
|
/// `prepared_evaluation_elements` don't match or is longer then
|
||||||
/// [`u16::MAX`]
|
/// [`u16::MAX`]
|
||||||
pub fn batch_evaluate_finish<
|
pub fn batch_blind_evaluate_finish<
|
||||||
'a,
|
'a,
|
||||||
'b,
|
'b,
|
||||||
R: RngCore + CryptoRng,
|
R: RngCore + CryptoRng,
|
||||||
@@ -398,6 +399,29 @@ where
|
|||||||
Ok(PoprfServerBatchEvaluateFinishResult { messages, proof })
|
Ok(PoprfServerBatchEvaluateFinishResult { messages, proof })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the output of the VOPRF on the server side
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// [`Error::Input`] if the `input` is longer then [`u16::MAX`].
|
||||||
|
pub fn evaluate(
|
||||||
|
&self,
|
||||||
|
input: &[u8],
|
||||||
|
info: Option<&[u8]>,
|
||||||
|
) -> Result<Output<<CS as CipherSuite>::Hash>> {
|
||||||
|
let input_element = hash_to_group::<CS>(input, Mode::Poprf)?;
|
||||||
|
if CS::Group::is_identity_elem(input_element).into() {
|
||||||
|
return Err(Error::Input);
|
||||||
|
};
|
||||||
|
|
||||||
|
let tweak = compute_tweak::<CS>(self.sk, info)?;
|
||||||
|
|
||||||
|
let evaluated_element = input_element * &CS::Group::invert_scalar(tweak);
|
||||||
|
|
||||||
|
let issued_element = CS::Group::serialize_elem(evaluated_element);
|
||||||
|
|
||||||
|
server_evaluate_hash_input::<CS>(input, info, issued_element)
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves the server's public key
|
/// Retrieves the server's public key
|
||||||
pub fn get_public_key(&self) -> <CS::Group as Group>::Elem {
|
pub fn get_public_key(&self) -> <CS::Group as Group>::Elem {
|
||||||
self.pk
|
self.pk
|
||||||
@@ -808,9 +832,9 @@ mod tests {
|
|||||||
let info = b"info";
|
let info = b"info";
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let server = PoprfServer::<CS>::new(&mut rng).unwrap();
|
let server = PoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let client_blind_result = PoprfClient::<CS>::blind(&mut rng, input).unwrap();
|
let client_blind_result = PoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
let server_result = server
|
let server_result = server
|
||||||
.evaluate(&mut rng, &client_blind_result.message, Some(info))
|
.blind_evaluate(&mut rng, &client_blind_result.message, Some(info))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let client_finalize_result = client_blind_result
|
let client_finalize_result = client_blind_result
|
||||||
.state
|
.state
|
||||||
@@ -835,9 +859,9 @@ mod tests {
|
|||||||
let info = b"info";
|
let info = b"info";
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let server = PoprfServer::<CS>::new(&mut rng).unwrap();
|
let server = PoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let client_blind_result = PoprfClient::<CS>::blind(&mut rng, input).unwrap();
|
let client_blind_result = PoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
let server_result = server
|
let server_result = server
|
||||||
.evaluate(&mut rng, &client_blind_result.message, Some(info))
|
.blind_evaluate(&mut rng, &client_blind_result.message, Some(info))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let wrong_pk = {
|
let wrong_pk = {
|
||||||
let dst = GenericArray::from(STR_HASH_TO_GROUP)
|
let dst = GenericArray::from(STR_HASH_TO_GROUP)
|
||||||
@@ -855,6 +879,43 @@ mod tests {
|
|||||||
assert!(client_finalize_result.is_err());
|
assert!(client_finalize_result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn verifiable_server_evaluate<CS: CipherSuite>()
|
||||||
|
where
|
||||||
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
|
{
|
||||||
|
let input = b"input";
|
||||||
|
let info = Some(b"info".as_slice());
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let client_blind_result = PoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
|
let server = PoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
|
let server_result = server
|
||||||
|
.blind_evaluate(&mut rng, &client_blind_result.message, info)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let client_finalize = client_blind_result
|
||||||
|
.state
|
||||||
|
.finalize(
|
||||||
|
input,
|
||||||
|
&server_result.message,
|
||||||
|
&server_result.proof,
|
||||||
|
server.get_public_key(),
|
||||||
|
info,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// We expect the outputs from client and server to be equal given an identical
|
||||||
|
// input
|
||||||
|
let server_evaluate = server.evaluate(input, info).unwrap();
|
||||||
|
assert_eq!(client_finalize, server_evaluate);
|
||||||
|
|
||||||
|
// We expect the outputs from client and server to be different given different
|
||||||
|
// inputs
|
||||||
|
let wrong_input = b"wrong input";
|
||||||
|
let server_evaluate = server.evaluate(wrong_input, info).unwrap();
|
||||||
|
assert!(client_finalize != server_evaluate);
|
||||||
|
}
|
||||||
|
|
||||||
fn zeroize_verifiable_client<CS: CipherSuite>()
|
fn zeroize_verifiable_client<CS: CipherSuite>()
|
||||||
where
|
where
|
||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
@@ -864,7 +925,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let input = b"input";
|
let input = b"input";
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let client_blind_result = PoprfClient::<CS>::blind(&mut rng, input).unwrap();
|
let client_blind_result = PoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
|
|
||||||
let mut state = client_blind_result.state;
|
let mut state = client_blind_result.state;
|
||||||
unsafe { ptr::drop_in_place(&mut state) };
|
unsafe { ptr::drop_in_place(&mut state) };
|
||||||
@@ -888,9 +949,9 @@ mod tests {
|
|||||||
let info = b"info";
|
let info = b"info";
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let server = PoprfServer::<CS>::new(&mut rng).unwrap();
|
let server = PoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let client_blind_result = PoprfClient::<CS>::blind(&mut rng, input).unwrap();
|
let client_blind_result = PoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
let server_result = server
|
let server_result = server
|
||||||
.evaluate(&mut rng, &client_blind_result.message, Some(info))
|
.blind_evaluate(&mut rng, &client_blind_result.message, Some(info))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut state = server;
|
let mut state = server;
|
||||||
@@ -916,6 +977,7 @@ mod tests {
|
|||||||
|
|
||||||
verifiable_retrieval::<Ristretto255>();
|
verifiable_retrieval::<Ristretto255>();
|
||||||
verifiable_bad_public_key::<Ristretto255>();
|
verifiable_bad_public_key::<Ristretto255>();
|
||||||
|
verifiable_server_evaluate::<Ristretto255>();
|
||||||
|
|
||||||
zeroize_verifiable_client::<Ristretto255>();
|
zeroize_verifiable_client::<Ristretto255>();
|
||||||
zeroize_verifiable_server::<Ristretto255>();
|
zeroize_verifiable_server::<Ristretto255>();
|
||||||
@@ -923,6 +985,7 @@ mod tests {
|
|||||||
|
|
||||||
verifiable_retrieval::<NistP256>();
|
verifiable_retrieval::<NistP256>();
|
||||||
verifiable_bad_public_key::<NistP256>();
|
verifiable_bad_public_key::<NistP256>();
|
||||||
|
verifiable_server_evaluate::<NistP256>();
|
||||||
|
|
||||||
zeroize_verifiable_client::<NistP256>();
|
zeroize_verifiable_client::<NistP256>();
|
||||||
zeroize_verifiable_server::<NistP256>();
|
zeroize_verifiable_server::<NistP256>();
|
||||||
|
|||||||
@@ -101,8 +101,9 @@ fn test_vectors() -> Result<()> {
|
|||||||
assert_ne!(ristretto_oprf_tvs.len(), 0);
|
assert_ne!(ristretto_oprf_tvs.len(), 0);
|
||||||
test_oprf_seed_to_key::<Ristretto255>(&ristretto_oprf_tvs)?;
|
test_oprf_seed_to_key::<Ristretto255>(&ristretto_oprf_tvs)?;
|
||||||
test_oprf_blind::<Ristretto255>(&ristretto_oprf_tvs)?;
|
test_oprf_blind::<Ristretto255>(&ristretto_oprf_tvs)?;
|
||||||
test_oprf_evaluate::<Ristretto255>(&ristretto_oprf_tvs)?;
|
test_oprf_blind_evaluate::<Ristretto255>(&ristretto_oprf_tvs)?;
|
||||||
test_oprf_finalize::<Ristretto255>(&ristretto_oprf_tvs)?;
|
test_oprf_finalize::<Ristretto255>(&ristretto_oprf_tvs)?;
|
||||||
|
test_oprf_evaluate::<Ristretto255>(&ristretto_oprf_tvs)?;
|
||||||
|
|
||||||
let ristretto_voprf_tvs = json_to_test_vectors!(
|
let ristretto_voprf_tvs = json_to_test_vectors!(
|
||||||
rfc,
|
rfc,
|
||||||
@@ -112,8 +113,9 @@ fn test_vectors() -> Result<()> {
|
|||||||
assert_ne!(ristretto_voprf_tvs.len(), 0);
|
assert_ne!(ristretto_voprf_tvs.len(), 0);
|
||||||
test_voprf_seed_to_key::<Ristretto255>(&ristretto_voprf_tvs)?;
|
test_voprf_seed_to_key::<Ristretto255>(&ristretto_voprf_tvs)?;
|
||||||
test_voprf_blind::<Ristretto255>(&ristretto_voprf_tvs)?;
|
test_voprf_blind::<Ristretto255>(&ristretto_voprf_tvs)?;
|
||||||
test_voprf_evaluate::<Ristretto255>(&ristretto_voprf_tvs)?;
|
test_voprf_blind_evaluate::<Ristretto255>(&ristretto_voprf_tvs)?;
|
||||||
test_voprf_finalize::<Ristretto255>(&ristretto_voprf_tvs)?;
|
test_voprf_finalize::<Ristretto255>(&ristretto_voprf_tvs)?;
|
||||||
|
test_voprf_evaluate::<Ristretto255>(&ristretto_voprf_tvs)?;
|
||||||
|
|
||||||
let ristretto_poprf_tvs = json_to_test_vectors!(
|
let ristretto_poprf_tvs = json_to_test_vectors!(
|
||||||
rfc,
|
rfc,
|
||||||
@@ -123,8 +125,9 @@ fn test_vectors() -> Result<()> {
|
|||||||
assert_ne!(ristretto_poprf_tvs.len(), 0);
|
assert_ne!(ristretto_poprf_tvs.len(), 0);
|
||||||
test_poprf_seed_to_key::<Ristretto255>(&ristretto_poprf_tvs)?;
|
test_poprf_seed_to_key::<Ristretto255>(&ristretto_poprf_tvs)?;
|
||||||
test_poprf_blind::<Ristretto255>(&ristretto_poprf_tvs)?;
|
test_poprf_blind::<Ristretto255>(&ristretto_poprf_tvs)?;
|
||||||
test_poprf_evaluate::<Ristretto255>(&ristretto_poprf_tvs)?;
|
test_poprf_blind_evaluate::<Ristretto255>(&ristretto_poprf_tvs)?;
|
||||||
test_poprf_finalize::<Ristretto255>(&ristretto_poprf_tvs)?;
|
test_poprf_finalize::<Ristretto255>(&ristretto_poprf_tvs)?;
|
||||||
|
test_poprf_evaluate::<Ristretto255>(&ristretto_poprf_tvs)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let p256_oprf_tvs =
|
let p256_oprf_tvs =
|
||||||
@@ -132,24 +135,27 @@ fn test_vectors() -> Result<()> {
|
|||||||
assert_ne!(p256_oprf_tvs.len(), 0);
|
assert_ne!(p256_oprf_tvs.len(), 0);
|
||||||
test_oprf_seed_to_key::<NistP256>(&p256_oprf_tvs)?;
|
test_oprf_seed_to_key::<NistP256>(&p256_oprf_tvs)?;
|
||||||
test_oprf_blind::<NistP256>(&p256_oprf_tvs)?;
|
test_oprf_blind::<NistP256>(&p256_oprf_tvs)?;
|
||||||
test_oprf_evaluate::<NistP256>(&p256_oprf_tvs)?;
|
test_oprf_blind_evaluate::<NistP256>(&p256_oprf_tvs)?;
|
||||||
test_oprf_finalize::<NistP256>(&p256_oprf_tvs)?;
|
test_oprf_finalize::<NistP256>(&p256_oprf_tvs)?;
|
||||||
|
test_oprf_evaluate::<NistP256>(&p256_oprf_tvs)?;
|
||||||
|
|
||||||
let p256_voprf_tvs =
|
let p256_voprf_tvs =
|
||||||
json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("VOPRF"));
|
json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("VOPRF"));
|
||||||
assert_ne!(p256_voprf_tvs.len(), 0);
|
assert_ne!(p256_voprf_tvs.len(), 0);
|
||||||
test_voprf_seed_to_key::<NistP256>(&p256_voprf_tvs)?;
|
test_voprf_seed_to_key::<NistP256>(&p256_voprf_tvs)?;
|
||||||
test_voprf_blind::<NistP256>(&p256_voprf_tvs)?;
|
test_voprf_blind::<NistP256>(&p256_voprf_tvs)?;
|
||||||
test_voprf_evaluate::<NistP256>(&p256_voprf_tvs)?;
|
test_voprf_blind_evaluate::<NistP256>(&p256_voprf_tvs)?;
|
||||||
test_voprf_finalize::<NistP256>(&p256_voprf_tvs)?;
|
test_voprf_finalize::<NistP256>(&p256_voprf_tvs)?;
|
||||||
|
test_voprf_evaluate::<NistP256>(&p256_voprf_tvs)?;
|
||||||
|
|
||||||
let p256_poprf_tvs =
|
let p256_poprf_tvs =
|
||||||
json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("POPRF"));
|
json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("POPRF"));
|
||||||
assert_ne!(p256_poprf_tvs.len(), 0);
|
assert_ne!(p256_poprf_tvs.len(), 0);
|
||||||
test_poprf_seed_to_key::<NistP256>(&p256_poprf_tvs)?;
|
test_poprf_seed_to_key::<NistP256>(&p256_poprf_tvs)?;
|
||||||
test_poprf_blind::<NistP256>(&p256_poprf_tvs)?;
|
test_poprf_blind::<NistP256>(&p256_poprf_tvs)?;
|
||||||
test_poprf_evaluate::<NistP256>(&p256_poprf_tvs)?;
|
test_poprf_blind_evaluate::<NistP256>(&p256_poprf_tvs)?;
|
||||||
test_poprf_finalize::<NistP256>(&p256_poprf_tvs)?;
|
test_poprf_finalize::<NistP256>(&p256_poprf_tvs)?;
|
||||||
|
test_poprf_evaluate::<NistP256>(&p256_poprf_tvs)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -286,7 +292,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tests sksm, blinded_element -> evaluation_element
|
// Tests sksm, blinded_element -> evaluation_element
|
||||||
fn test_oprf_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
fn test_oprf_blind_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
||||||
where
|
where
|
||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
@@ -294,7 +300,7 @@ where
|
|||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
for i in 0..parameters.input.len() {
|
for i in 0..parameters.input.len() {
|
||||||
let server = OprfServer::<CS>::new_with_key(¶meters.sksm)?;
|
let server = OprfServer::<CS>::new_with_key(¶meters.sksm)?;
|
||||||
let message = server.evaluate(&BlindedElement::deserialize(
|
let message = server.blind_evaluate(&BlindedElement::deserialize(
|
||||||
¶meters.blinded_element[i],
|
¶meters.blinded_element[i],
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
@@ -307,7 +313,7 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_voprf_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
fn test_voprf_blind_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
||||||
where
|
where
|
||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
@@ -323,10 +329,11 @@ where
|
|||||||
blinded_elements.push(BlindedElement::deserialize(blinded_element_bytes)?);
|
blinded_elements.push(BlindedElement::deserialize(blinded_element_bytes)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let prepared_evaluation_elements = server.batch_evaluate_prepare(blinded_elements.iter());
|
let prepared_evaluation_elements =
|
||||||
|
server.batch_blind_evaluate_prepare(blinded_elements.iter());
|
||||||
let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
|
let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
|
||||||
let VoprfServerBatchEvaluateFinishResult { messages, proof } =
|
let VoprfServerBatchEvaluateFinishResult { messages, proof } = server
|
||||||
server.batch_evaluate_finish(&mut rng, blinded_elements.iter(), &prepared_elements)?;
|
.batch_blind_evaluate_finish(&mut rng, blinded_elements.iter(), &prepared_elements)?;
|
||||||
let messages: Vec<_> = messages.collect();
|
let messages: Vec<_> = messages.collect();
|
||||||
|
|
||||||
for (parameter, message) in parameters.evaluation_element.iter().zip(messages) {
|
for (parameter, message) in parameters.evaluation_element.iter().zip(messages) {
|
||||||
@@ -338,7 +345,7 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_poprf_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
fn test_poprf_blind_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
||||||
where
|
where
|
||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
@@ -357,10 +364,10 @@ where
|
|||||||
let PoprfServerBatchEvaluatePrepareResult {
|
let PoprfServerBatchEvaluatePrepareResult {
|
||||||
prepared_evaluation_elements,
|
prepared_evaluation_elements,
|
||||||
prepared_tweak,
|
prepared_tweak,
|
||||||
} = server.batch_evaluate_prepare(blinded_elements.iter(), Some(¶meters.info))?;
|
} = server.batch_blind_evaluate_prepare(blinded_elements.iter(), Some(¶meters.info))?;
|
||||||
let prepared_evaluation_elements: Vec<_> = prepared_evaluation_elements.collect();
|
let prepared_evaluation_elements: Vec<_> = prepared_evaluation_elements.collect();
|
||||||
let PoprfServerBatchEvaluateFinishResult { messages, proof } =
|
let PoprfServerBatchEvaluateFinishResult { messages, proof } =
|
||||||
PoprfServer::batch_evaluate_finish::<_, _, Vec<_>>(
|
PoprfServer::batch_blind_evaluate_finish::<_, _, Vec<_>>(
|
||||||
&mut rng,
|
&mut rng,
|
||||||
blinded_elements.iter(),
|
blinded_elements.iter(),
|
||||||
&prepared_evaluation_elements,
|
&prepared_evaluation_elements,
|
||||||
@@ -476,3 +483,56 @@ where
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests input, sksm -> output
|
||||||
|
fn test_oprf_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
||||||
|
where
|
||||||
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
|
{
|
||||||
|
for parameters in tvs {
|
||||||
|
for i in 0..parameters.input.len() {
|
||||||
|
let server = OprfServer::<CS>::new_with_key(¶meters.sksm)?;
|
||||||
|
|
||||||
|
let server_evaluate_result = server.evaluate(¶meters.input[i])?;
|
||||||
|
|
||||||
|
assert_eq!(¶meters.output[i], &server_evaluate_result.to_vec());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_voprf_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
||||||
|
where
|
||||||
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
|
{
|
||||||
|
for parameters in tvs {
|
||||||
|
for i in 0..parameters.input.len() {
|
||||||
|
let server = VoprfServer::<CS>::new_with_key(¶meters.sksm)?;
|
||||||
|
|
||||||
|
let server_evaluate_result = server.evaluate(¶meters.input[i])?;
|
||||||
|
|
||||||
|
assert_eq!(¶meters.output[i], &server_evaluate_result.to_vec());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_poprf_evaluate<CS: CipherSuite>(tvs: &[VOPRFTestVectorParameters]) -> Result<()>
|
||||||
|
where
|
||||||
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
|
{
|
||||||
|
for parameters in tvs {
|
||||||
|
for i in 0..parameters.input.len() {
|
||||||
|
let server = PoprfServer::<CS>::new_with_key(¶meters.sksm)?;
|
||||||
|
|
||||||
|
let server_evaluate_result =
|
||||||
|
server.evaluate(¶meters.input[i], Some(¶meters.info))?;
|
||||||
|
|
||||||
|
assert_eq!(¶meters.output[i], &server_evaluate_result.to_vec());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
+75
-23
@@ -19,8 +19,9 @@ use generic_array::GenericArray;
|
|||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
use crate::common::{
|
use crate::common::{
|
||||||
derive_keypair, deterministic_blind_unchecked, generate_proof, i2osp_2, verify_proof,
|
derive_keypair, deterministic_blind_unchecked, generate_proof, hash_to_group, i2osp_2,
|
||||||
BlindedElement, EvaluationElement, Mode, PreparedEvaluationElement, Proof, STR_FINALIZE,
|
server_evaluate_hash_input, verify_proof, BlindedElement, EvaluationElement, Mode,
|
||||||
|
PreparedEvaluationElement, Proof, STR_FINALIZE,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use crate::serialization::serde::{Element, Scalar};
|
use crate::serialization::serde::{Element, Scalar};
|
||||||
@@ -253,13 +254,13 @@ where
|
|||||||
/// Computes the second step for the multiplicative blinding version of
|
/// Computes the second step for the multiplicative blinding version of
|
||||||
/// DH-OPRF. This message is sent from the server (who holds the OPRF key)
|
/// DH-OPRF. This message is sent from the server (who holds the OPRF key)
|
||||||
/// to the client.
|
/// to the client.
|
||||||
pub fn evaluate<R: RngCore + CryptoRng>(
|
pub fn blind_evaluate<R: RngCore + CryptoRng>(
|
||||||
&self,
|
&self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
blinded_element: &BlindedElement<CS>,
|
blinded_element: &BlindedElement<CS>,
|
||||||
) -> VoprfServerEvaluateResult<CS> {
|
) -> VoprfServerEvaluateResult<CS> {
|
||||||
let mut prepared_evaluation_elements =
|
let mut prepared_evaluation_elements =
|
||||||
self.batch_evaluate_prepare(iter::once(blinded_element));
|
self.batch_blind_evaluate_prepare(iter::once(blinded_element));
|
||||||
let prepared_evaluation_element = [prepared_evaluation_elements.next().unwrap()];
|
let prepared_evaluation_element = [prepared_evaluation_elements.next().unwrap()];
|
||||||
|
|
||||||
// This can't fail because we know the size of the inputs.
|
// This can't fail because we know the size of the inputs.
|
||||||
@@ -267,7 +268,7 @@ where
|
|||||||
mut messages,
|
mut messages,
|
||||||
proof,
|
proof,
|
||||||
} = self
|
} = self
|
||||||
.batch_evaluate_finish(
|
.batch_blind_evaluate_finish(
|
||||||
rng,
|
rng,
|
||||||
iter::once(blinded_element),
|
iter::once(blinded_element),
|
||||||
&prepared_evaluation_element,
|
&prepared_evaluation_element,
|
||||||
@@ -286,7 +287,7 @@ where
|
|||||||
/// [`Error::Batch`] if the number of `blinded_elements` and
|
/// [`Error::Batch`] if the number of `blinded_elements` and
|
||||||
/// `evaluation_elements` don't match or is longer then [`u16::MAX`]
|
/// `evaluation_elements` don't match or is longer then [`u16::MAX`]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub fn batch_evaluate<'a, R: RngCore + CryptoRng, I>(
|
pub fn batch_blind_evaluate<'a, R: RngCore + CryptoRng, I>(
|
||||||
&self,
|
&self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
blinded_elements: &'a I,
|
blinded_elements: &'a I,
|
||||||
@@ -297,10 +298,10 @@ where
|
|||||||
<&'a I as IntoIterator>::IntoIter: ExactSizeIterator,
|
<&'a I as IntoIterator>::IntoIter: ExactSizeIterator,
|
||||||
{
|
{
|
||||||
let prepared_evaluation_elements = self
|
let prepared_evaluation_elements = self
|
||||||
.batch_evaluate_prepare(blinded_elements.into_iter())
|
.batch_blind_evaluate_prepare(blinded_elements.into_iter())
|
||||||
.collect();
|
.collect();
|
||||||
let VoprfServerBatchEvaluateFinishResult { messages, proof } = self
|
let VoprfServerBatchEvaluateFinishResult { messages, proof } = self
|
||||||
.batch_evaluate_finish::<_, _, Vec<_>>(
|
.batch_blind_evaluate_finish::<_, _, Vec<_>>(
|
||||||
rng,
|
rng,
|
||||||
blinded_elements.into_iter(),
|
blinded_elements.into_iter(),
|
||||||
&prepared_evaluation_elements,
|
&prepared_evaluation_elements,
|
||||||
@@ -310,11 +311,11 @@ where
|
|||||||
Ok(VoprfServerBatchEvaluateResult { messages, proof })
|
Ok(VoprfServerBatchEvaluateResult { messages, proof })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alternative version of `batch_evaluate` without
|
/// Alternative version of `batch_blind_evaluate` without memory allocation.
|
||||||
/// memory allocation. Returned [`PreparedEvaluationElement`] have to be
|
/// Returned [`PreparedEvaluationElement`] have to be
|
||||||
/// [`collect`](Iterator::collect)ed and passed into
|
/// [`collect`](Iterator::collect)ed and passed into
|
||||||
/// [`batch_evaluate_finish`](Self::batch_evaluate_finish).
|
/// [`batch_blind_evaluate_finish`](Self::batch_blind_evaluate_finish).
|
||||||
pub fn batch_evaluate_prepare<'a, I: Iterator<Item = &'a BlindedElement<CS>>>(
|
pub fn batch_blind_evaluate_prepare<'a, I: Iterator<Item = &'a BlindedElement<CS>>>(
|
||||||
&self,
|
&self,
|
||||||
blinded_elements: I,
|
blinded_elements: I,
|
||||||
) -> VoprfServerBatchEvaluatePreparedEvaluationElements<CS, I>
|
) -> VoprfServerBatchEvaluatePreparedEvaluationElements<CS, I>
|
||||||
@@ -328,13 +329,13 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`batch_evaluate_prepare`](Self::batch_evaluate_prepare) for more
|
/// See [`batch_blind_evaluate_prepare`](Self::batch_blind_evaluate_prepare)
|
||||||
/// details.
|
/// for more details.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// [`Error::Batch`] if the number of `blinded_elements` and
|
/// [`Error::Batch`] if the number of `blinded_elements` and
|
||||||
/// `evaluation_elements` don't match or is longer then [`u16::MAX`]
|
/// `evaluation_elements` don't match or is longer then [`u16::MAX`]
|
||||||
pub fn batch_evaluate_finish<
|
pub fn batch_blind_evaluate_finish<
|
||||||
'a,
|
'a,
|
||||||
'b,
|
'b,
|
||||||
R: RngCore + CryptoRng,
|
R: RngCore + CryptoRng,
|
||||||
@@ -371,6 +372,22 @@ where
|
|||||||
Ok(VoprfServerBatchEvaluateFinishResult { messages, proof })
|
Ok(VoprfServerBatchEvaluateFinishResult { messages, proof })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the output of the POPRF on the server side
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// [`Error::Input`] if the `input` is longer then [`u16::MAX`].
|
||||||
|
pub fn evaluate(&self, input: &[u8]) -> Result<Output<<CS as CipherSuite>::Hash>> {
|
||||||
|
let input_element = hash_to_group::<CS>(input, Mode::Voprf)?;
|
||||||
|
if CS::Group::is_identity_elem(input_element).into() {
|
||||||
|
return Err(Error::Input);
|
||||||
|
};
|
||||||
|
let evaluated_element = input_element * &self.sk;
|
||||||
|
|
||||||
|
let issued_element = CS::Group::serialize_elem(evaluated_element);
|
||||||
|
|
||||||
|
server_evaluate_hash_input::<CS>(input, None, issued_element)
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves the server's public key
|
/// Retrieves the server's public key
|
||||||
pub fn get_public_key(&self) -> <CS::Group as Group>::Elem {
|
pub fn get_public_key(&self) -> <CS::Group as Group>::Elem {
|
||||||
self.pk
|
self.pk
|
||||||
@@ -431,7 +448,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Concrete type of [`EvaluationElement`]s returned by
|
/// Concrete type of [`EvaluationElement`]s returned by
|
||||||
/// [`VoprfServer::batch_evaluate_prepare`].
|
/// [`VoprfServer::batch_blind_evaluate_prepare`].
|
||||||
pub type VoprfServerBatchEvaluatePreparedEvaluationElements<CS, I> = Map<
|
pub type VoprfServerBatchEvaluatePreparedEvaluationElements<CS, I> = Map<
|
||||||
Zip<I, Repeat<<<CS as CipherSuite>::Group as Group>::Scalar>>,
|
Zip<I, Repeat<<<CS as CipherSuite>::Group as Group>::Scalar>>,
|
||||||
fn(
|
fn(
|
||||||
@@ -608,7 +625,7 @@ mod tests {
|
|||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let client_blind_result = VoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
let client_blind_result = VoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let server_result = server.evaluate(&mut rng, &client_blind_result.message);
|
let server_result = server.blind_evaluate(&mut rng, &client_blind_result.message);
|
||||||
let client_finalize_result = client_blind_result
|
let client_finalize_result = client_blind_result
|
||||||
.state
|
.state
|
||||||
.finalize(
|
.finalize(
|
||||||
@@ -642,10 +659,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let prepared_evaluation_elements: Vec<_> = server
|
let prepared_evaluation_elements: Vec<_> = server
|
||||||
.batch_evaluate_prepare(client_messages.iter())
|
.batch_blind_evaluate_prepare(client_messages.iter())
|
||||||
.collect();
|
.collect();
|
||||||
let VoprfServerBatchEvaluateFinishResult { messages, proof } = server
|
let VoprfServerBatchEvaluateFinishResult { messages, proof } = server
|
||||||
.batch_evaluate_finish(
|
.batch_blind_evaluate_finish(
|
||||||
&mut rng,
|
&mut rng,
|
||||||
client_messages.iter(),
|
client_messages.iter(),
|
||||||
&prepared_evaluation_elements,
|
&prepared_evaluation_elements,
|
||||||
@@ -690,10 +707,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let prepared_evaluation_elements: Vec<_> = server
|
let prepared_evaluation_elements: Vec<_> = server
|
||||||
.batch_evaluate_prepare(client_messages.iter())
|
.batch_blind_evaluate_prepare(client_messages.iter())
|
||||||
.collect();
|
.collect();
|
||||||
let VoprfServerBatchEvaluateFinishResult { messages, proof } = server
|
let VoprfServerBatchEvaluateFinishResult { messages, proof } = server
|
||||||
.batch_evaluate_finish(
|
.batch_blind_evaluate_finish(
|
||||||
&mut rng,
|
&mut rng,
|
||||||
client_messages.iter(),
|
client_messages.iter(),
|
||||||
&prepared_evaluation_elements,
|
&prepared_evaluation_elements,
|
||||||
@@ -720,7 +737,7 @@ mod tests {
|
|||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let client_blind_result = VoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
let client_blind_result = VoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let server_result = server.evaluate(&mut rng, &client_blind_result.message);
|
let server_result = server.blind_evaluate(&mut rng, &client_blind_result.message);
|
||||||
let wrong_pk = {
|
let wrong_pk = {
|
||||||
let dst = GenericArray::from(STR_HASH_TO_GROUP)
|
let dst = GenericArray::from(STR_HASH_TO_GROUP)
|
||||||
.concat(create_context_string::<CS>(Mode::Oprf));
|
.concat(create_context_string::<CS>(Mode::Oprf));
|
||||||
@@ -736,6 +753,39 @@ mod tests {
|
|||||||
assert!(client_finalize_result.is_err());
|
assert!(client_finalize_result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn verifiable_server_evaluate<CS: CipherSuite>()
|
||||||
|
where
|
||||||
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||||
|
{
|
||||||
|
let input = b"input";
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let client_blind_result = VoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
|
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
|
let server_result = server.blind_evaluate(&mut rng, &client_blind_result.message);
|
||||||
|
|
||||||
|
let client_finalize = client_blind_result
|
||||||
|
.state
|
||||||
|
.finalize(
|
||||||
|
input,
|
||||||
|
&server_result.message,
|
||||||
|
&server_result.proof,
|
||||||
|
server.get_public_key(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// We expect the outputs from client and server to be equal given an identical
|
||||||
|
// input
|
||||||
|
let server_evaluate = server.evaluate(input).unwrap();
|
||||||
|
assert_eq!(client_finalize, server_evaluate);
|
||||||
|
|
||||||
|
// We expect the outputs from client and server to be different given different
|
||||||
|
// inputs
|
||||||
|
let wrong_input = b"wrong input";
|
||||||
|
let server_evaluate = server.evaluate(wrong_input).unwrap();
|
||||||
|
assert!(client_finalize != server_evaluate);
|
||||||
|
}
|
||||||
|
|
||||||
fn zeroize_voprf_client<CS: CipherSuite>()
|
fn zeroize_voprf_client<CS: CipherSuite>()
|
||||||
where
|
where
|
||||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||||
@@ -769,7 +819,7 @@ mod tests {
|
|||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let client_blind_result = VoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
let client_blind_result = VoprfClient::<CS>::blind(input, &mut rng).unwrap();
|
||||||
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
|
||||||
let server_result = server.evaluate(&mut rng, &client_blind_result.message);
|
let server_result = server.blind_evaluate(&mut rng, &client_blind_result.message);
|
||||||
|
|
||||||
let mut state = server;
|
let mut state = server;
|
||||||
unsafe { ptr::drop_in_place(&mut state) };
|
unsafe { ptr::drop_in_place(&mut state) };
|
||||||
@@ -796,6 +846,7 @@ mod tests {
|
|||||||
verifiable_batch_retrieval::<Ristretto255>();
|
verifiable_batch_retrieval::<Ristretto255>();
|
||||||
verifiable_bad_public_key::<Ristretto255>();
|
verifiable_bad_public_key::<Ristretto255>();
|
||||||
verifiable_batch_bad_public_key::<Ristretto255>();
|
verifiable_batch_bad_public_key::<Ristretto255>();
|
||||||
|
verifiable_server_evaluate::<Ristretto255>();
|
||||||
|
|
||||||
zeroize_voprf_client::<Ristretto255>();
|
zeroize_voprf_client::<Ristretto255>();
|
||||||
zeroize_voprf_server::<Ristretto255>();
|
zeroize_voprf_server::<Ristretto255>();
|
||||||
@@ -805,6 +856,7 @@ mod tests {
|
|||||||
verifiable_batch_retrieval::<NistP256>();
|
verifiable_batch_retrieval::<NistP256>();
|
||||||
verifiable_bad_public_key::<NistP256>();
|
verifiable_bad_public_key::<NistP256>();
|
||||||
verifiable_batch_bad_public_key::<NistP256>();
|
verifiable_batch_bad_public_key::<NistP256>();
|
||||||
|
verifiable_server_evaluate::<NistP256>();
|
||||||
|
|
||||||
zeroize_voprf_client::<NistP256>();
|
zeroize_voprf_client::<NistP256>();
|
||||||
zeroize_voprf_server::<NistP256>();
|
zeroize_voprf_server::<NistP256>();
|
||||||
|
|||||||
Reference in New Issue
Block a user