Adding crate-level documentation (#9)
This commit is contained in:
@@ -16,6 +16,8 @@ jobs:
|
|||||||
- u64_backend
|
- u64_backend
|
||||||
- u32_backend
|
- u32_backend
|
||||||
- p256,u64_backend
|
- p256,u64_backend
|
||||||
|
frontend_feature:
|
||||||
|
- serialize
|
||||||
toolchain:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
- 1.51.0
|
- 1.51.0
|
||||||
@@ -42,7 +44,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --no-default-features --features std --features ${{ matrix.backend_feature }}
|
args: --no-default-features --features ${{ matrix.frontend_feature }},std --features ${{ matrix.backend_feature }}
|
||||||
|
|
||||||
build-no-std:
|
build-no-std:
|
||||||
name: Build with no-std on ${{ matrix.target }}
|
name: Build with no-std on ${{ matrix.target }}
|
||||||
@@ -59,11 +61,13 @@ jobs:
|
|||||||
- u64_backend
|
- u64_backend
|
||||||
- u32_backend
|
- u32_backend
|
||||||
- p256,u64_backend
|
- p256,u64_backend
|
||||||
|
frontend_feature:
|
||||||
|
- serialize
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: hecrj/setup-rust-action@v1
|
- uses: hecrj/setup-rust-action@v1
|
||||||
- run: rustup target add ${{ matrix.target }}
|
- run: rustup target add ${{ matrix.target }}
|
||||||
- run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.backend_feature }}
|
- run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.frontend_feature }} --features ${{ matrix.backend_feature }}
|
||||||
|
|
||||||
|
|
||||||
clippy:
|
clippy:
|
||||||
|
|||||||
+4
-2
@@ -10,13 +10,15 @@ readme = "README.md"
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["u64_backend"]
|
default = ["u64_backend", "serialize"]
|
||||||
p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"]
|
p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"]
|
||||||
std = ["curve25519-dalek/std", "getrandom", "rand/std", "rand/std_rng", "num-bigint/std", "num-integer/std", "num-traits/std"]
|
std = ["curve25519-dalek/std", "getrandom", "rand/std", "rand/std_rng", "num-bigint/std", "num-integer/std", "num-traits/std"]
|
||||||
u64_backend = ["curve25519-dalek/u64_backend"]
|
u64_backend = ["curve25519-dalek/u64_backend"]
|
||||||
u32_backend = ["curve25519-dalek/u32_backend"]
|
u32_backend = ["curve25519-dalek/u32_backend"]
|
||||||
|
serialize = ["serde", "base64", "generic-array/serde", "curve25519-dalek/serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
base64 = { version = "0.13", default-features = false, features = ["alloc"], optional = true }
|
||||||
constant_time_eq = "0.1"
|
constant_time_eq = "0.1"
|
||||||
curve25519-dalek = { version = "3", default-features = false }
|
curve25519-dalek = { version = "3", default-features = false }
|
||||||
digest = "0.9"
|
digest = "0.9"
|
||||||
@@ -33,7 +35,7 @@ p256_ = { package = "p256", version = "0.9", default-features = false, features
|
|||||||
rand = { version = "0.8", default-features = false }
|
rand = { version = "0.8", default-features = false }
|
||||||
subtle = { version = "2.3", default-features = false }
|
subtle = { version = "2.3", default-features = false }
|
||||||
zeroize = { version = "1", features = ["zeroize_derive"] }
|
zeroize = { version = "1", features = ["zeroize_derive"] }
|
||||||
serde = { version = "1", default-features = false, features = ["alloc", "derive"] }
|
serde = { version = "1", default-features = false, features = ["alloc", "derive"], optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
getrandom = { version = "0.2", features = ["js"], optional = true }
|
getrandom = { version = "0.2", features = ["js"], optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,35 @@
|
|||||||
# voprf 
|
# voprf 
|
||||||
An implementation of a (verifiable) oblivious pseudorandom function (VOPRF)
|
An implementation of a (verifiable) oblivious pseudorandom function (VOPRF)
|
||||||
|
|
||||||
|
A VOPRF is a verifiable oblivious pseudorandom function, a protocol between a client and a server. The regular (non-verifiable) OPRF is also supported in this implementation.
|
||||||
|
|
||||||
|
This implementation is based on the [Internet Draft for VOPRF](https://github.com/cfrg/draft-irtf-cfrg-voprf).
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The API can be found [here](https://docs.rs/voprf/) along with an example for usage.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
Add the following line to the dependencies of your `Cargo.toml`:
|
||||||
|
|
||||||
|
```
|
||||||
|
voprf = "0.1.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Minimum Supported Rust Version
|
||||||
|
|
||||||
|
Rust **1.51** or higher.
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
The author of this code is Kevin Lewi
|
||||||
|
([@kevinlewi](https://github.com/kevinlewi)) .
|
||||||
|
To learn more about contributing to this project, [see this document](./CONTRIBUTING.md).
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|||||||
+468
-3
@@ -7,9 +7,462 @@
|
|||||||
//!
|
//!
|
||||||
//! Note: This implementation is in sync with
|
//! Note: This implementation is in sync with
|
||||||
//! [draft-irtf-cfrg-opaque-07](https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-07.html),
|
//! [draft-irtf-cfrg-opaque-07](https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-07.html),
|
||||||
//! but this specification is subject to change, until the final version published by the IETF.
|
//! but this specification is subject to change, until the final version
|
||||||
|
//! published by the IETF.
|
||||||
//!
|
//!
|
||||||
|
//! # Overview
|
||||||
//!
|
//!
|
||||||
|
//! A verifiable oblivious pseudorandom function is a protocol that is
|
||||||
|
//! evaluated between a client and a server. They must first agree on a
|
||||||
|
//! collection of primitives to be kept consistent throughout protocol
|
||||||
|
//! execution. These include:
|
||||||
|
//! - a finite cyclic group along with a point representation, and
|
||||||
|
//! - a hashing function.
|
||||||
|
//!
|
||||||
|
//! We will use the following choices in this example:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use voprf::CipherSuite;
|
||||||
|
//! struct Default;
|
||||||
|
//! impl CipherSuite for Default {
|
||||||
|
//! type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! type Hash = sha2::Sha512;
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Modes of Operation
|
||||||
|
//!
|
||||||
|
//! VOPRF can be used in two modes:
|
||||||
|
//! - [Base Mode](#base-mode), which corresponds to a normal OPRF evaluation with no
|
||||||
|
//! support for the verification of the OPRF outputs
|
||||||
|
//! - [Verifiable Mode](#verifiable-mode), which corresponds to an OPRF evaluation where
|
||||||
|
//! the outputs can be verified against a server public key
|
||||||
|
//!
|
||||||
|
//! In either mode, the protocol begins with a client blinding, followed by
|
||||||
|
//! a server evaluation, and finishes with a client finalization.
|
||||||
|
//!
|
||||||
|
//! ## Base Mode
|
||||||
|
//!
|
||||||
|
//! In base mode, a [NonVerifiableClient] interacts with a
|
||||||
|
//! [NonVerifiableServer] to compute the output of the VOPRF.
|
||||||
|
//!
|
||||||
|
//! ### Server Setup
|
||||||
|
//!
|
||||||
|
//! The protocol begins with a setup phase, in which the server must run
|
||||||
|
//! [NonVerifiableServer::new()] to produce an instance of itself. This
|
||||||
|
//! instance must be persisted on the server and used for online
|
||||||
|
//! client evaluations.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! use voprf::NonVerifiableServer;
|
||||||
|
//! use rand::{rngs::OsRng, RngCore};
|
||||||
|
//!
|
||||||
|
//! let mut server_rng = OsRng;
|
||||||
|
//! let server = NonVerifiableServer::<Default>::new(&mut server_rng)
|
||||||
|
//! .expect("Unable to construct server");
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Client Blinding
|
||||||
|
//!
|
||||||
|
//! In the first step, the client chooses an input, and runs
|
||||||
|
//! [NonVerifiableClient::blind] to produce a [NonVerifiableClientBlindResult],
|
||||||
|
//! which consists of a [BlindedElement] to be sent to the server and a
|
||||||
|
//! [NonVerifiableClient] which must be persisted on the client for the final
|
||||||
|
//! step of the VOPRF protocol.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! use voprf::NonVerifiableClient;
|
||||||
|
//! use rand::{rngs::OsRng, RngCore};
|
||||||
|
//!
|
||||||
|
//! let mut client_rng = OsRng;
|
||||||
|
//! let client_blind_result = NonVerifiableClient::<Default>::blind(
|
||||||
|
//! b"input",
|
||||||
|
//! &mut client_rng,
|
||||||
|
//! ).expect("Unable to construct client");
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Server Evaluation
|
||||||
|
//!
|
||||||
|
//! In the second step, the server takes as input the message from
|
||||||
|
//! [NonVerifiableClient::blind] (a [BlindedElement]), and runs
|
||||||
|
//! [NonVerifiableServer::evaluate] to produce a
|
||||||
|
//! [NonVerifiableServerEvaluateResult], which consists of an
|
||||||
|
//! [EvaluationElement] to be sent to the client.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::NonVerifiableClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_blind_result = NonVerifiableClient::<Default>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # use voprf::NonVerifiableServer;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server = NonVerifiableServer::<Default>::new(&mut server_rng)
|
||||||
|
//! # .expect("Unable to construct server");
|
||||||
|
//! use voprf::Metadata;
|
||||||
|
//! let server_evaluate_result = server.evaluate(
|
||||||
|
//! client_blind_result.message,
|
||||||
|
//! &Metadata::none(),
|
||||||
|
//! ).expect("Unable to perform server evaluate");
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Client Finalization
|
||||||
|
//!
|
||||||
|
//! In the final step, the client takes as input the message from
|
||||||
|
//! [NonVerifiableServer::evaluate] (an [EvaluationElement]), and runs
|
||||||
|
//! [NonVerifiableClient::finalize] to produce a
|
||||||
|
//! [NonVerifiableClientFinalizeResult], which consists of an
|
||||||
|
//! output for the protocol.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::NonVerifiableClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_blind_result = NonVerifiableClient::<Default>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # use voprf::NonVerifiableServer;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server = NonVerifiableServer::<Default>::new(&mut server_rng)
|
||||||
|
//! # .expect("Unable to construct server");
|
||||||
|
//! # let server_evaluate_result = server.evaluate(
|
||||||
|
//! # client_blind_result.message,
|
||||||
|
//! # &Metadata::none(),
|
||||||
|
//! # ).expect("Unable to perform server evaluate");
|
||||||
|
//! use voprf::Metadata;
|
||||||
|
//! let client_finalize_result = client_blind_result.state.finalize(
|
||||||
|
//! server_evaluate_result.message,
|
||||||
|
//! &Metadata::none(),
|
||||||
|
//! ).expect("Unable to perform client finalization");
|
||||||
|
//!
|
||||||
|
//! println!("VOPRF output: {:?}", client_finalize_result.output.to_vec());
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Verifiable Mode
|
||||||
|
//!
|
||||||
|
//! In verifiable mode, a [VerifiableClient] interacts with a
|
||||||
|
//! [VerifiableServer] to 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 public key. If the proof fails to verify,
|
||||||
|
//! then the client does not receive an output.
|
||||||
|
//!
|
||||||
|
//! In batch mode, a single proof can be used for multiple VOPRF evaluations.
|
||||||
|
//! See [the batching section](#batching)
|
||||||
|
//! for more details on how to perform batch evaluations.
|
||||||
|
//!
|
||||||
|
//! ### Server Setup
|
||||||
|
//!
|
||||||
|
//! The protocol begins with a setup phase, in which the server must run
|
||||||
|
//! [VerifiableServer::new()] to produce an instance of itself. This
|
||||||
|
//! instance must be persisted on the server and used for online
|
||||||
|
//! client evaluations.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! use voprf::VerifiableServer;
|
||||||
|
//! use rand::{rngs::OsRng, RngCore};
|
||||||
|
//!
|
||||||
|
//! let mut server_rng = OsRng;
|
||||||
|
//! let server = VerifiableServer::<Default>::new(&mut server_rng)
|
||||||
|
//! .expect("Unable to construct server");
|
||||||
|
//!
|
||||||
|
//! // To be sent to the client
|
||||||
|
//! println!("Server public key: {:?}", server.get_public_key());
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The public key should be sent to the client, since the client will
|
||||||
|
//! need it in the final step of the protocol in order to complete
|
||||||
|
//! the evaluation of the VOPRF.
|
||||||
|
//!
|
||||||
|
//! ### Client Blinding
|
||||||
|
//!
|
||||||
|
//! In the first step, the client chooses an input, and runs
|
||||||
|
//! [VerifiableClient::blind] to produce a [VerifiableClientBlindResult],
|
||||||
|
//! which consists of a [BlindedElement] to be sent to the server and a
|
||||||
|
//! [VerifiableClient] which must be persisted on the client for the final
|
||||||
|
//! step of the VOPRF protocol.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! use voprf::VerifiableClient;
|
||||||
|
//! use rand::{rngs::OsRng, RngCore};
|
||||||
|
//!
|
||||||
|
//! let mut client_rng = OsRng;
|
||||||
|
//! let client_blind_result = VerifiableClient::<Default>::blind(
|
||||||
|
//! b"input",
|
||||||
|
//! &mut client_rng,
|
||||||
|
//! ).expect("Unable to construct client");
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Server Evaluation
|
||||||
|
//!
|
||||||
|
//! In the second step, the server takes as input the message from
|
||||||
|
//! [VerifiableClient::blind] (a [BlindedElement]), and runs
|
||||||
|
//! [VerifiableServer::evaluate] to produce a
|
||||||
|
//! [VerifiableServerEvaluateResult], which consists of an
|
||||||
|
//! [EvaluationElement] to be sent to the client along with a proof.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::VerifiableClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_blind_result = VerifiableClient::<Default>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # use voprf::VerifiableServer;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server = VerifiableServer::<Default>::new(&mut server_rng)
|
||||||
|
//! # .expect("Unable to construct server");
|
||||||
|
//! use voprf::Metadata;
|
||||||
|
//! let server_evaluate_result = server.evaluate(
|
||||||
|
//! &mut server_rng,
|
||||||
|
//! client_blind_result.message,
|
||||||
|
//! &Metadata::none(),
|
||||||
|
//! ).expect("Unable to perform server evaluate");
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Client Finalization
|
||||||
|
//!
|
||||||
|
//! In the final step, the client takes as input the message from
|
||||||
|
//! [VerifiableServer::evaluate] (an [EvaluationElement]),
|
||||||
|
//! the proof, and the server's public key, and runs
|
||||||
|
//! [VerifiableClient::finalize] to produce a
|
||||||
|
//! [VerifiableClientFinalizeResult], which consists of an
|
||||||
|
//! output for the protocol.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::VerifiableClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_blind_result = VerifiableClient::<Default>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # use voprf::VerifiableServer;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server = VerifiableServer::<Default>::new(&mut server_rng)
|
||||||
|
//! # .expect("Unable to construct server");
|
||||||
|
//! # let server_evaluate_result = server.evaluate(
|
||||||
|
//! # &mut server_rng,
|
||||||
|
//! # client_blind_result.message,
|
||||||
|
//! # &Metadata::none(),
|
||||||
|
//! # ).expect("Unable to perform server evaluate");
|
||||||
|
//! use voprf::Metadata;
|
||||||
|
//! let client_finalize_result = client_blind_result.state.finalize(
|
||||||
|
//! server_evaluate_result.message,
|
||||||
|
//! server_evaluate_result.proof,
|
||||||
|
//! server.get_public_key(),
|
||||||
|
//! &Metadata::none(),
|
||||||
|
//! ).expect("Unable to perform client finalization");
|
||||||
|
//!
|
||||||
|
//! println!("VOPRF output: {:?}", client_finalize_result.output.to_vec());
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Advanced Usage
|
||||||
|
//!
|
||||||
|
//! There are two additional (and optional) extensions to the core VOPRF
|
||||||
|
//! protocol: support for batching of evaluations, and support for public
|
||||||
|
//! metadata.
|
||||||
|
//!
|
||||||
|
//! ## Batching
|
||||||
|
//!
|
||||||
|
//! It is sometimes desirable to generate only a single, constant-size
|
||||||
|
//! proof for an unbounded number of VOPRF evaluations (on arbitrary inputs).
|
||||||
|
//! [VerifiableClient] and [VerifiableServer] support a batch API for
|
||||||
|
//! handling this case. In the following example, we show how to use
|
||||||
|
//! the batch API to produce a single proof for 10 parallel
|
||||||
|
//! VOPRF evaluations.
|
||||||
|
//!
|
||||||
|
//! First, the client produces 10 blindings, storing their resulting
|
||||||
|
//! states and messages:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::VerifiableClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! let mut client_rng = OsRng;
|
||||||
|
//! let mut client_states = vec![];
|
||||||
|
//! let mut client_messages = vec![];
|
||||||
|
//! for _ in 0..10 {
|
||||||
|
//! let client_blind_result = VerifiableClient::<Default>::blind(
|
||||||
|
//! b"input",
|
||||||
|
//! &mut client_rng,
|
||||||
|
//! ).expect("Unable to construct client");
|
||||||
|
//! client_states.push(client_blind_result.state);
|
||||||
|
//! client_messages.push(client_blind_result.message);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Next, the server calls the [VerifiableServer::batch_evaluate]
|
||||||
|
//! function on a set of client messages, to produce a corresponding
|
||||||
|
//! set of messages to be returned to the client (returned in the same order),
|
||||||
|
//! along with a single proof:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::VerifiableClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let mut client_states = vec![];
|
||||||
|
//! # let mut client_messages = vec![];
|
||||||
|
//! # for _ in 0..10 {
|
||||||
|
//! # let client_blind_result = VerifiableClient::<Default>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # client_states.push(client_blind_result.state);
|
||||||
|
//! # client_messages.push(client_blind_result.message);
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::Metadata;
|
||||||
|
//! # use voprf::VerifiableServer;
|
||||||
|
//! let mut server_rng = OsRng;
|
||||||
|
//! # let server = VerifiableServer::<Default>::new(&mut server_rng)
|
||||||
|
//! # .expect("Unable to construct server");
|
||||||
|
//! let server_batch_evaluate_result = server.batch_evaluate(
|
||||||
|
//! &mut server_rng,
|
||||||
|
//! &client_messages,
|
||||||
|
//! &Metadata::none(),
|
||||||
|
//! ).expect("Unable to perform server batch evaluate");
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Then, the client calls [VerifiableClient::batch_finalize] on
|
||||||
|
//! the client states saved from the first step, along with the messages
|
||||||
|
//! returned by the server (constructing a [BatchFinalizeInput]), along with the
|
||||||
|
//! server's proof, in order to produce a vector of outputs if the proof
|
||||||
|
//! verifies correctly.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use voprf::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::VerifiableClient;
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let mut client_states = vec![];
|
||||||
|
//! # let mut client_messages = vec![];
|
||||||
|
//! # for _ in 0..10 {
|
||||||
|
//! # let client_blind_result = VerifiableClient::<Default>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # client_states.push(client_blind_result.state);
|
||||||
|
//! # client_messages.push(client_blind_result.message);
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::Metadata;
|
||||||
|
//! # use voprf::VerifiableServer;
|
||||||
|
//! use voprf::BatchFinalizeInput;
|
||||||
|
//! let mut server_rng = OsRng;
|
||||||
|
//! # let server = VerifiableServer::<Default>::new(&mut server_rng)
|
||||||
|
//! # .expect("Unable to construct server");
|
||||||
|
//! # let server_batch_evaluate_result = server.batch_evaluate(
|
||||||
|
//! # &mut server_rng,
|
||||||
|
//! # &client_messages,
|
||||||
|
//! # &Metadata::none(),
|
||||||
|
//! # ).expect("Unable to perform server batch evaluate");
|
||||||
|
//! let batch_finalize_input = BatchFinalizeInput::new(
|
||||||
|
//! client_states,
|
||||||
|
//! server_batch_evaluate_result.messages,
|
||||||
|
//! );
|
||||||
|
//! let client_batch_finalize_result = VerifiableClient::batch_finalize(
|
||||||
|
//! batch_finalize_input,
|
||||||
|
//! server_batch_evaluate_result.proof,
|
||||||
|
//! server.get_public_key(),
|
||||||
|
//! &Metadata::none(),
|
||||||
|
//! ).expect("Unable to perform client batch finalization");
|
||||||
|
//!
|
||||||
|
//! println!("VOPRF batch outputs: {:?}", client_batch_finalize_result.outputs);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Metadata
|
||||||
|
//!
|
||||||
|
//! The optional metadata parameter included in the protocol allows clients and
|
||||||
|
//! servers (of either mode) to cryptographically bind additional data to the
|
||||||
|
//! VOPRF output. This metadata is known to both parties at the start of the protocol,
|
||||||
|
//! and is inserted under the server's evaluate step and the client's finalize step.
|
||||||
|
//! This metadata can be constructed with some type of higher-level domain separation
|
||||||
|
//! to avoid cross-protocol attacks or related issues.
|
||||||
|
//!
|
||||||
|
//! The default metadata simply consists of the empty vector of bytes, but a custom
|
||||||
|
//! metadata can be specified, for example, by: `Metadata(b"custom metadata")`.
|
||||||
|
//!
|
||||||
|
//! # Features
|
||||||
|
//!
|
||||||
|
//! - The `serialize` feature, enabled by default, provides convenience functions for serializing and deserializing with
|
||||||
|
//! [serde](https://serde.rs/).
|
||||||
|
//!
|
||||||
|
//! - The `u32_backend` and `u64_backend` features are re-exported from
|
||||||
|
//! [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) and allow for selecting
|
||||||
|
//! the corresponding backend for the curve arithmetic used. The `u64_backend` feature is included as the default.
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "bench"), deny(missing_docs))]
|
#![cfg_attr(not(feature = "bench"), deny(missing_docs))]
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
@@ -20,11 +473,23 @@ extern crate alloc;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod serialization;
|
mod serialization;
|
||||||
|
|
||||||
pub mod ciphersuite;
|
mod ciphersuite;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod group;
|
pub mod group;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
pub mod voprf;
|
mod voprf;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
|
||||||
|
pub use rand;
|
||||||
|
|
||||||
|
pub use crate::ciphersuite::CipherSuite;
|
||||||
|
pub use crate::voprf::{
|
||||||
|
BatchFinalizeInput, BlindedElement, EvaluationElement, Metadata, NonVerifiableClient,
|
||||||
|
NonVerifiableClientBlindResult, NonVerifiableClientFinalizeResult, NonVerifiableServer,
|
||||||
|
NonVerifiableServerEvaluateResult, VerifiableClient, VerifiableClientBlindResult,
|
||||||
|
VerifiableClientFinalizeResult, VerifiableServer, VerifiableServerEvaluateResult,
|
||||||
|
};
|
||||||
|
|||||||
@@ -18,11 +18,80 @@ use crate::{
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use generic_array::{typenum::Unsigned, GenericArray};
|
use generic_array::{typenum::Unsigned, GenericArray};
|
||||||
|
|
||||||
|
/// Inner macro used for deriving `serde`'s `Serialize` and `Deserialize` traits.
|
||||||
|
macro_rules! impl_serialize_and_deserialize_for {
|
||||||
|
($t:ident) => {
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl<CS: CipherSuite> serde::Serialize for $t<CS> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
if serializer.is_human_readable() {
|
||||||
|
serializer.serialize_str(&base64::encode(&self.serialize()))
|
||||||
|
} else {
|
||||||
|
serializer.serialize_bytes(&self.serialize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl<'de, CS: CipherSuite> serde::Deserialize<'de> for $t<CS> {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
if deserializer.is_human_readable() {
|
||||||
|
let s = <&str>::deserialize(deserializer)?;
|
||||||
|
$t::<CS>::deserialize(&base64::decode(s).map_err(serde::de::Error::custom)?)
|
||||||
|
.map_err(serde::de::Error::custom)
|
||||||
|
} else {
|
||||||
|
struct ByteVisitor<CS: CipherSuite> {
|
||||||
|
marker: core::marker::PhantomData<CS>,
|
||||||
|
}
|
||||||
|
impl<'de, CS: CipherSuite> serde::de::Visitor<'de> for ByteVisitor<CS> {
|
||||||
|
type Value = $t<CS>;
|
||||||
|
fn expecting(
|
||||||
|
&self,
|
||||||
|
formatter: &mut core::fmt::Formatter,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
formatter.write_str(core::concat!(
|
||||||
|
"the byte representation of a ",
|
||||||
|
core::stringify!($t)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
$t::<CS>::deserialize(value).map_err(|_| {
|
||||||
|
serde::de::Error::invalid_value(
|
||||||
|
serde::de::Unexpected::Bytes(value),
|
||||||
|
&core::concat!(
|
||||||
|
"invalid byte sequence for ",
|
||||||
|
core::stringify!($t)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_bytes(ByteVisitor::<CS> {
|
||||||
|
marker: core::marker::PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
// Serialization and Deserialization for High-Level API //
|
// Serialization and Deserialization for High-Level API //
|
||||||
// ==================================================== //
|
// ==================================================== //
|
||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl_serialize_and_deserialize_for!(NonVerifiableClient);
|
||||||
|
|
||||||
impl<CS: CipherSuite> NonVerifiableClient<CS> {
|
impl<CS: CipherSuite> NonVerifiableClient<CS> {
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
@@ -47,6 +116,8 @@ impl<CS: CipherSuite> NonVerifiableClient<CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_serialize_and_deserialize_for!(VerifiableClient);
|
||||||
|
|
||||||
impl<CS: CipherSuite> VerifiableClient<CS> {
|
impl<CS: CipherSuite> VerifiableClient<CS> {
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
@@ -80,6 +151,8 @@ impl<CS: CipherSuite> VerifiableClient<CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_serialize_and_deserialize_for!(NonVerifiableServer);
|
||||||
|
|
||||||
impl<CS: CipherSuite> NonVerifiableServer<CS> {
|
impl<CS: CipherSuite> NonVerifiableServer<CS> {
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
@@ -99,6 +172,8 @@ impl<CS: CipherSuite> NonVerifiableServer<CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_serialize_and_deserialize_for!(VerifiableServer);
|
||||||
|
|
||||||
impl<CS: CipherSuite> VerifiableServer<CS> {
|
impl<CS: CipherSuite> VerifiableServer<CS> {
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
@@ -124,6 +199,8 @@ impl<CS: CipherSuite> VerifiableServer<CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_serialize_and_deserialize_for!(Proof);
|
||||||
|
|
||||||
impl<CS: CipherSuite> Proof<CS> {
|
impl<CS: CipherSuite> Proof<CS> {
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
@@ -147,6 +224,8 @@ impl<CS: CipherSuite> Proof<CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_serialize_and_deserialize_for!(BlindedElement);
|
||||||
|
|
||||||
impl<CS: CipherSuite> BlindedElement<CS> {
|
impl<CS: CipherSuite> BlindedElement<CS> {
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
@@ -161,6 +240,8 @@ impl<CS: CipherSuite> BlindedElement<CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_serialize_and_deserialize_for!(EvaluationElement);
|
||||||
|
|
||||||
impl<CS: CipherSuite> EvaluationElement<CS> {
|
impl<CS: CipherSuite> EvaluationElement<CS> {
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use crate::{
|
|||||||
group::Group,
|
group::Group,
|
||||||
tests::{mock_rng::CycleRng, parser::*},
|
tests::{mock_rng::CycleRng, parser::*},
|
||||||
voprf::{
|
voprf::{
|
||||||
BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableServer, Proof,
|
BatchFinalizeInput, BlindedElement, EvaluationElement, Metadata, NonVerifiableClient,
|
||||||
VerifiableClient, VerifiableServer,
|
NonVerifiableServer, Proof, VerifiableClient, VerifiableServer,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
@@ -180,14 +180,16 @@ fn test_base_blind<CS: CipherSuite>(
|
|||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
for i in 0..parameters.input.len() {
|
for i in 0..parameters.input.len() {
|
||||||
let mut rng = CycleRng::new(parameters.blind[i].to_vec());
|
let mut rng = CycleRng::new(parameters.blind[i].to_vec());
|
||||||
let (client, blinded_element) =
|
let client_result = NonVerifiableClient::<CS>::blind(¶meters.input[i], &mut rng)?;
|
||||||
NonVerifiableClient::<CS>::blind(¶meters.input[i], &mut rng)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
¶meters.blind[i],
|
¶meters.blind[i],
|
||||||
&CS::Group::scalar_as_bytes(client.get_blind()).to_vec()
|
&CS::Group::scalar_as_bytes(client_result.state.get_blind()).to_vec()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
¶meters.blinded_element[i],
|
||||||
|
&client_result.message.serialize()
|
||||||
);
|
);
|
||||||
assert_eq!(¶meters.blinded_element[i], &blinded_element.serialize());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -200,14 +202,17 @@ fn test_verifiable_blind<CS: CipherSuite>(
|
|||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
for i in 0..parameters.input.len() {
|
for i in 0..parameters.input.len() {
|
||||||
let mut rng = CycleRng::new(parameters.blind[i].to_vec());
|
let mut rng = CycleRng::new(parameters.blind[i].to_vec());
|
||||||
let (client, blinded_element) =
|
let client_blind_result =
|
||||||
VerifiableClient::<CS>::blind(¶meters.input[i], &mut rng)?;
|
VerifiableClient::<CS>::blind(¶meters.input[i], &mut rng)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
¶meters.blind[i],
|
¶meters.blind[i],
|
||||||
&CS::Group::scalar_as_bytes(client.get_blind()).to_vec()
|
&CS::Group::scalar_as_bytes(client_blind_result.state.get_blind()).to_vec()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
¶meters.blinded_element[i],
|
||||||
|
&client_blind_result.message.serialize()
|
||||||
);
|
);
|
||||||
assert_eq!(¶meters.blinded_element[i], &blinded_element.serialize());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -220,14 +225,14 @@ fn test_base_evaluate<CS: CipherSuite>(
|
|||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
for i in 0..parameters.input.len() {
|
for i in 0..parameters.input.len() {
|
||||||
let server = NonVerifiableServer::<CS>::new_with_key(¶meters.sksm)?;
|
let server = NonVerifiableServer::<CS>::new_with_key(¶meters.sksm)?;
|
||||||
let evaluation_element = server.evaluate(
|
let server_result = server.evaluate(
|
||||||
BlindedElement::deserialize(¶meters.blinded_element[i])?,
|
BlindedElement::deserialize(¶meters.blinded_element[i])?,
|
||||||
¶meters.info,
|
&Metadata(parameters.info.clone()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
¶meters.evaluation_element[i],
|
¶meters.evaluation_element[i],
|
||||||
&evaluation_element.serialize()
|
&server_result.message.serialize()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,17 +251,20 @@ fn test_verifiable_evaluate<CS: CipherSuite>(
|
|||||||
blinded_elements.push(BlindedElement::deserialize(&blinded_element_bytes)?);
|
blinded_elements.push(BlindedElement::deserialize(&blinded_element_bytes)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (evaluation_elements, proof) =
|
let batch_evaluate_result = server.batch_evaluate(
|
||||||
server.batch_evaluate(&mut rng, &blinded_elements, ¶meters.info)?;
|
&mut rng,
|
||||||
|
&blinded_elements,
|
||||||
|
&Metadata(parameters.info.clone()),
|
||||||
|
)?;
|
||||||
|
|
||||||
for i in 0..parameters.evaluation_element.len() {
|
for i in 0..parameters.evaluation_element.len() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
¶meters.evaluation_element[i],
|
¶meters.evaluation_element[i],
|
||||||
&evaluation_elements[i].serialize(),
|
&batch_evaluate_result.messages[i].serialize(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(¶meters.proof, &proof.serialize());
|
assert_eq!(¶meters.proof, &batch_evaluate_result.proof.serialize());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -274,12 +282,15 @@ fn test_base_finalize<CS: CipherSuite>(
|
|||||||
))?,
|
))?,
|
||||||
);
|
);
|
||||||
|
|
||||||
let output = client.finalize(
|
let client_finalize_result = client.finalize(
|
||||||
EvaluationElement::deserialize(¶meters.evaluation_element[i])?,
|
EvaluationElement::deserialize(¶meters.evaluation_element[i])?,
|
||||||
¶meters.info,
|
&Metadata(parameters.info.clone()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
assert_eq!(¶meters.output[i], &output.to_vec());
|
assert_eq!(
|
||||||
|
¶meters.output[i],
|
||||||
|
&client_finalize_result.output.to_vec()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -289,8 +300,6 @@ fn test_verifiable_finalize<CS: CipherSuite>(
|
|||||||
tvs: &[VOPRFTestVectorParameters],
|
tvs: &[VOPRFTestVectorParameters],
|
||||||
) -> Result<(), InternalError> {
|
) -> Result<(), InternalError> {
|
||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
let mut clients_and_evaluation_elements = vec![];
|
|
||||||
|
|
||||||
let mut clients = vec![];
|
let mut clients = vec![];
|
||||||
for i in 0..parameters.input.len() {
|
for i in 0..parameters.input.len() {
|
||||||
let client = VerifiableClient::<CS>::from_data_and_blind(
|
let client = VerifiableClient::<CS>::from_data_and_blind(
|
||||||
@@ -305,22 +314,26 @@ fn test_verifiable_finalize<CS: CipherSuite>(
|
|||||||
clients.push(client.clone());
|
clients.push(client.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..parameters.input.len() {
|
let batch_finalize_input = BatchFinalizeInput::new(
|
||||||
let evaluation_element =
|
clients,
|
||||||
EvaluationElement::deserialize(¶meters.evaluation_element[i])?;
|
parameters
|
||||||
clients_and_evaluation_elements.push((&clients[i], evaluation_element));
|
.evaluation_element
|
||||||
}
|
.iter()
|
||||||
|
.map(|x| EvaluationElement::deserialize(x).unwrap())
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
let outputs = VerifiableClient::batch_finalize(
|
let batch_result = VerifiableClient::batch_finalize(
|
||||||
&clients_and_evaluation_elements,
|
batch_finalize_input,
|
||||||
Proof::deserialize(¶meters.proof)?,
|
Proof::deserialize(¶meters.proof)?,
|
||||||
CS::Group::from_element_slice(GenericArray::from_slice(¶meters.pksm))?,
|
CS::Group::from_element_slice(GenericArray::from_slice(¶meters.pksm))?,
|
||||||
¶meters.info,
|
&Metadata(parameters.info.clone()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parameters.output,
|
parameters.output,
|
||||||
outputs
|
batch_result
|
||||||
|
.outputs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arr| arr.to_vec())
|
.map(|arr| arr.to_vec())
|
||||||
.collect::<Vec<Vec<u8>>>()
|
.collect::<Vec<Vec<u8>>>()
|
||||||
|
|||||||
+179
-49
@@ -101,15 +101,15 @@ impl<CS: CipherSuite> NonVerifiableClient<CS> {
|
|||||||
pub fn blind<R: RngCore + CryptoRng>(
|
pub fn blind<R: RngCore + CryptoRng>(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
blinding_factor_rng: &mut R,
|
blinding_factor_rng: &mut R,
|
||||||
) -> Result<(Self, BlindedElement<CS>), InternalError> {
|
) -> Result<NonVerifiableClientBlindResult<CS>, InternalError> {
|
||||||
let (blind, blinded_element) = blind::<CS, _>(input, blinding_factor_rng, Mode::Base)?;
|
let (blind, blinded_element) = blind::<CS, _>(input, blinding_factor_rng, Mode::Base)?;
|
||||||
Ok((
|
Ok(NonVerifiableClientBlindResult {
|
||||||
Self {
|
state: Self {
|
||||||
data: input.to_vec(),
|
data: input.to_vec(),
|
||||||
blind,
|
blind,
|
||||||
},
|
},
|
||||||
BlindedElement(blinded_element),
|
message: BlindedElement(blinded_element),
|
||||||
))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the third step for the multiplicative blinding version of DH-OPRF, in which
|
/// Computes the third step for the multiplicative blinding version of DH-OPRF, in which
|
||||||
@@ -117,16 +117,18 @@ impl<CS: CipherSuite> NonVerifiableClient<CS> {
|
|||||||
pub fn finalize(
|
pub fn finalize(
|
||||||
&self,
|
&self,
|
||||||
evaluation_element: EvaluationElement<CS>,
|
evaluation_element: EvaluationElement<CS>,
|
||||||
info: &[u8],
|
metadata: &Metadata,
|
||||||
) -> Result<GenericArray<u8, <CS::Hash as Digest>::OutputSize>, InternalError> {
|
) -> Result<NonVerifiableClientFinalizeResult<CS>, InternalError> {
|
||||||
let unblinded_element =
|
let unblinded_element =
|
||||||
evaluation_element.0 * &<CS::Group as Group>::scalar_invert(&self.blind);
|
evaluation_element.0 * &<CS::Group as Group>::scalar_invert(&self.blind);
|
||||||
let outputs = finalize_after_unblind::<CS>(
|
let outputs = finalize_after_unblind::<CS>(
|
||||||
&[(self.data.clone(), unblinded_element)],
|
&[(self.data.clone(), unblinded_element)],
|
||||||
info,
|
&metadata.0,
|
||||||
Mode::Base,
|
Mode::Base,
|
||||||
)?;
|
)?;
|
||||||
Ok(outputs[0].clone())
|
Ok(NonVerifiableClientFinalizeResult {
|
||||||
|
output: outputs[0].clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -150,17 +152,17 @@ impl<CS: CipherSuite> VerifiableClient<CS> {
|
|||||||
pub fn blind<R: RngCore + CryptoRng>(
|
pub fn blind<R: RngCore + CryptoRng>(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
blinding_factor_rng: &mut R,
|
blinding_factor_rng: &mut R,
|
||||||
) -> Result<(Self, BlindedElement<CS>), InternalError> {
|
) -> Result<VerifiableClientBlindResult<CS>, InternalError> {
|
||||||
let (blind, blinded_element) =
|
let (blind, blinded_element) =
|
||||||
blind::<CS, _>(input, blinding_factor_rng, Mode::Verifiable)?;
|
blind::<CS, _>(input, blinding_factor_rng, Mode::Verifiable)?;
|
||||||
Ok((
|
Ok(VerifiableClientBlindResult {
|
||||||
Self {
|
state: Self {
|
||||||
data: input.to_vec(),
|
data: input.to_vec(),
|
||||||
blind,
|
blind,
|
||||||
blinded_element,
|
blinded_element,
|
||||||
},
|
},
|
||||||
BlindedElement(blinded_element),
|
message: BlindedElement(blinded_element),
|
||||||
))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the third step for the multiplicative blinding version of DH-OPRF, in which
|
/// Computes the third step for the multiplicative blinding version of DH-OPRF, in which
|
||||||
@@ -170,22 +172,28 @@ impl<CS: CipherSuite> VerifiableClient<CS> {
|
|||||||
evaluation_element: EvaluationElement<CS>,
|
evaluation_element: EvaluationElement<CS>,
|
||||||
proof: Proof<CS>,
|
proof: Proof<CS>,
|
||||||
pk: CS::Group,
|
pk: CS::Group,
|
||||||
info: &[u8],
|
metadata: &Metadata,
|
||||||
) -> Result<GenericArray<u8, <CS::Hash as Digest>::OutputSize>, InternalError> {
|
) -> Result<VerifiableClientFinalizeResult<CS>, InternalError> {
|
||||||
let outputs = Self::batch_finalize(&[(self, evaluation_element)], proof, pk, info)?;
|
let batch_finalize_input =
|
||||||
Ok(outputs[0].clone())
|
BatchFinalizeInput::new(vec![self.clone()], vec![evaluation_element]);
|
||||||
|
let batch_result = Self::batch_finalize(batch_finalize_input, proof, pk, metadata)?;
|
||||||
|
Ok(VerifiableClientFinalizeResult {
|
||||||
|
output: batch_result.outputs[0].clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows for batching of the finalization of multiple [VerifiableClient] and [EvaluationElement] pairs
|
/// Allows for batching of the finalization of multiple [VerifiableClient] and [EvaluationElement] pairs
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn batch_finalize(
|
pub fn batch_finalize(
|
||||||
clients_and_evaluation_elements: &[(&VerifiableClient<CS>, EvaluationElement<CS>)],
|
batch_finalize_input: BatchFinalizeInput<CS>,
|
||||||
proof: Proof<CS>,
|
proof: Proof<CS>,
|
||||||
pk: CS::Group,
|
pk: CS::Group,
|
||||||
info: &[u8],
|
metadata: &Metadata,
|
||||||
) -> Result<Vec<GenericArray<u8, <CS::Hash as Digest>::OutputSize>>, InternalError> {
|
) -> Result<VerifiableClientBatchFinalizeResult<CS>, InternalError> {
|
||||||
let batch_items: Vec<BatchItems<CS>> = clients_and_evaluation_elements
|
let batch_items: Vec<BatchItems<CS>> = batch_finalize_input
|
||||||
|
.clients
|
||||||
.iter()
|
.iter()
|
||||||
|
.zip(batch_finalize_input.messages.iter())
|
||||||
.map(|(client, evaluation_element)| BatchItems {
|
.map(|(client, evaluation_element)| BatchItems {
|
||||||
blind: client.blind,
|
blind: client.blind,
|
||||||
evaluation_element: evaluation_element.clone(),
|
evaluation_element: evaluation_element.clone(),
|
||||||
@@ -193,16 +201,22 @@ impl<CS: CipherSuite> VerifiableClient<CS> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let unblinded_elements = verifiable_unblind(&batch_items, pk, proof, info)?;
|
let unblinded_elements = verifiable_unblind(&batch_items, pk, proof, &metadata.0)?;
|
||||||
|
|
||||||
let inputs_and_unblinded_elements: Vec<(Vec<u8>, CS::Group)> =
|
let inputs_and_unblinded_elements: Vec<(Vec<u8>, CS::Group)> = batch_finalize_input
|
||||||
clients_and_evaluation_elements
|
.clients
|
||||||
.iter()
|
.iter()
|
||||||
.zip(unblinded_elements.iter())
|
.zip(unblinded_elements.iter())
|
||||||
.map(|((client, _), &unblinded_element)| (client.data.clone(), unblinded_element))
|
.map(|(client, &unblinded_element)| (client.data.clone(), unblinded_element))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
finalize_after_unblind::<CS>(&inputs_and_unblinded_elements, info, Mode::Verifiable)
|
Ok(VerifiableClientBatchFinalizeResult {
|
||||||
|
outputs: finalize_after_unblind::<CS>(
|
||||||
|
&inputs_and_unblinded_elements,
|
||||||
|
&metadata.0,
|
||||||
|
Mode::Verifiable,
|
||||||
|
)?,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -262,19 +276,21 @@ impl<CS: CipherSuite> NonVerifiableServer<CS> {
|
|||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
&self,
|
&self,
|
||||||
blinded_element: BlindedElement<CS>,
|
blinded_element: BlindedElement<CS>,
|
||||||
info: &[u8],
|
metadata: &Metadata,
|
||||||
) -> Result<EvaluationElement<CS>, InternalError> {
|
) -> Result<NonVerifiableServerEvaluateResult<CS>, InternalError> {
|
||||||
let context = [
|
let context = [
|
||||||
STR_CONTEXT,
|
STR_CONTEXT,
|
||||||
&get_context_string::<CS>(Mode::Base)?,
|
&get_context_string::<CS>(Mode::Base)?,
|
||||||
&serialize(info, 2)?,
|
&serialize(&metadata.0, 2)?,
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
let dst = [STR_HASH_TO_SCALAR, &get_context_string::<CS>(Mode::Base)?].concat();
|
let dst = [STR_HASH_TO_SCALAR, &get_context_string::<CS>(Mode::Base)?].concat();
|
||||||
let m = CS::Group::hash_to_scalar::<CS::Hash>(&context, &dst)?;
|
let m = CS::Group::hash_to_scalar::<CS::Hash>(&context, &dst)?;
|
||||||
let t = self.sk + &m;
|
let t = self.sk + &m;
|
||||||
let evaluation_element = blinded_element.0 * &CS::Group::scalar_invert(&t);
|
let evaluation_element = blinded_element.0 * &CS::Group::scalar_invert(&t);
|
||||||
Ok(EvaluationElement(evaluation_element))
|
Ok(NonVerifiableServerEvaluateResult {
|
||||||
|
message: EvaluationElement(evaluation_element),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,10 +337,13 @@ impl<CS: CipherSuite> VerifiableServer<CS> {
|
|||||||
&self,
|
&self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
blinded_element: BlindedElement<CS>,
|
blinded_element: BlindedElement<CS>,
|
||||||
info: &[u8],
|
metadata: &Metadata,
|
||||||
) -> Result<(EvaluationElement<CS>, Proof<CS>), InternalError> {
|
) -> Result<VerifiableServerEvaluateResult<CS>, InternalError> {
|
||||||
let (evaluation_elements, proof) = self.batch_evaluate(rng, &[blinded_element], info)?;
|
let batch_result = self.batch_evaluate(rng, &[blinded_element], metadata)?;
|
||||||
Ok((evaluation_elements[0].clone(), proof))
|
Ok(VerifiableServerEvaluateResult {
|
||||||
|
message: batch_result.messages[0].clone(),
|
||||||
|
proof: batch_result.proof,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows for batching of the evaluation of multiple [BlindedElement] messages from a [VerifiableClient]
|
/// Allows for batching of the evaluation of multiple [BlindedElement] messages from a [VerifiableClient]
|
||||||
@@ -332,12 +351,12 @@ impl<CS: CipherSuite> VerifiableServer<CS> {
|
|||||||
&self,
|
&self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
blinded_elements: &[BlindedElement<CS>],
|
blinded_elements: &[BlindedElement<CS>],
|
||||||
info: &[u8],
|
metadata: &Metadata,
|
||||||
) -> Result<(Vec<EvaluationElement<CS>>, Proof<CS>), InternalError> {
|
) -> Result<VerifiableServerBatchEvaluateResult<CS>, InternalError> {
|
||||||
let context = [
|
let context = [
|
||||||
STR_CONTEXT,
|
STR_CONTEXT,
|
||||||
&get_context_string::<CS>(Mode::Verifiable)?,
|
&get_context_string::<CS>(Mode::Verifiable)?,
|
||||||
&serialize(info, 2)?,
|
&serialize(&metadata.0, 2)?,
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
let dst = [
|
let dst = [
|
||||||
@@ -357,7 +376,10 @@ impl<CS: CipherSuite> VerifiableServer<CS> {
|
|||||||
|
|
||||||
let proof = generate_proof(rng, t, g, u, &evaluation_elements, blinded_elements)?;
|
let proof = generate_proof(rng, t, g, u, &evaluation_elements, blinded_elements)?;
|
||||||
|
|
||||||
Ok((evaluation_elements, proof))
|
Ok(VerifiableServerBatchEvaluateResult {
|
||||||
|
messages: evaluation_elements,
|
||||||
|
proof,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the server's public key
|
/// Retrieves the server's public key
|
||||||
@@ -366,6 +388,103 @@ impl<CS: CipherSuite> VerifiableServer<CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Optional Parameters //
|
||||||
|
//==================== //
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
/// Allows for implementations to specify an optional sequence of
|
||||||
|
/// public bytes that must be agreed-upon by the client and server
|
||||||
|
pub struct Metadata(pub Vec<u8>);
|
||||||
|
|
||||||
|
impl Default for Metadata {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Metadata {
|
||||||
|
/// Specifies no metadata (the default option)
|
||||||
|
pub fn none() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Convenience Structs //
|
||||||
|
//==================== //
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a non-verifiable client blind
|
||||||
|
pub struct NonVerifiableClientBlindResult<CS: CipherSuite> {
|
||||||
|
/// The state to be persisted on the client
|
||||||
|
pub state: NonVerifiableClient<CS>,
|
||||||
|
/// The message to send to the server
|
||||||
|
pub message: BlindedElement<CS>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a non-verifiable server evaluate
|
||||||
|
pub struct NonVerifiableServerEvaluateResult<CS: CipherSuite> {
|
||||||
|
/// The message to send to the client
|
||||||
|
pub message: EvaluationElement<CS>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a non-verifiable client finalize
|
||||||
|
pub struct NonVerifiableClientFinalizeResult<CS: CipherSuite> {
|
||||||
|
/// The output of the protocol
|
||||||
|
pub output: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a verifiable client blind
|
||||||
|
pub struct VerifiableClientBlindResult<CS: CipherSuite> {
|
||||||
|
/// The state to be persisted on the client
|
||||||
|
pub state: VerifiableClient<CS>,
|
||||||
|
/// The message to send to the server
|
||||||
|
pub message: BlindedElement<CS>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a verifiable server evaluate
|
||||||
|
pub struct VerifiableServerEvaluateResult<CS: CipherSuite> {
|
||||||
|
/// The message to send to the client
|
||||||
|
pub message: EvaluationElement<CS>,
|
||||||
|
/// The proof for the client to verify
|
||||||
|
pub proof: Proof<CS>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a verifiable server batch evaluate
|
||||||
|
pub struct VerifiableServerBatchEvaluateResult<CS: CipherSuite> {
|
||||||
|
/// The messages to send to the client
|
||||||
|
pub messages: Vec<EvaluationElement<CS>>,
|
||||||
|
/// The proof for the client to verify
|
||||||
|
pub proof: Proof<CS>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a verifiable client finalize
|
||||||
|
pub struct VerifiableClientFinalizeResult<CS: CipherSuite> {
|
||||||
|
/// The output of the protocol
|
||||||
|
pub output: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a verifiable client batch finalize
|
||||||
|
pub struct VerifiableClientBatchFinalizeResult<CS: CipherSuite> {
|
||||||
|
/// The output of the protocol
|
||||||
|
pub outputs: Vec<GenericArray<u8, <CS::Hash as Digest>::OutputSize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An input to the verifiable client batch finalize function, constructed
|
||||||
|
/// by aggregating clients and server messages
|
||||||
|
pub struct BatchFinalizeInput<CS: CipherSuite> {
|
||||||
|
clients: Vec<VerifiableClient<CS>>,
|
||||||
|
messages: Vec<EvaluationElement<CS>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<CS: CipherSuite> BatchFinalizeInput<CS> {
|
||||||
|
/// Create a new instance from a vector of clients and a vector of messages
|
||||||
|
pub fn new(clients: Vec<VerifiableClient<CS>>, messages: Vec<EvaluationElement<CS>>) -> Self {
|
||||||
|
Self { clients, messages }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////
|
///////////////////////////////////////////////
|
||||||
// Inner functions and Trait Implementations //
|
// Inner functions and Trait Implementations //
|
||||||
// ========================================= //
|
// ========================================= //
|
||||||
@@ -683,7 +802,7 @@ mod tests {
|
|||||||
let input = b"hunter2";
|
let input = b"hunter2";
|
||||||
let info = b"info";
|
let info = b"info";
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let (client, alpha) =
|
let client_blind_result =
|
||||||
NonVerifiableClient::<Ristretto255Sha512>::blind(&input[..], &mut rng).unwrap();
|
NonVerifiableClient::<Ristretto255Sha512>::blind(&input[..], &mut rng).unwrap();
|
||||||
let oprf_key_bytes = arr![
|
let oprf_key_bytes = arr![
|
||||||
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||||
@@ -691,10 +810,15 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let server =
|
let server =
|
||||||
NonVerifiableServer::<Ristretto255Sha512>::new_with_key(&oprf_key_bytes).unwrap();
|
NonVerifiableServer::<Ristretto255Sha512>::new_with_key(&oprf_key_bytes).unwrap();
|
||||||
let beta = server.evaluate(alpha, info).unwrap();
|
let server_result = server
|
||||||
let res = client.finalize(beta, info).unwrap();
|
.evaluate(client_blind_result.message, &Metadata(info.to_vec()))
|
||||||
|
.unwrap();
|
||||||
|
let client_finalize_result = client_blind_result
|
||||||
|
.state
|
||||||
|
.finalize(server_result.message, &Metadata(info.to_vec()))
|
||||||
|
.unwrap();
|
||||||
let res2 = prf(&input[..], &oprf_key_bytes, info);
|
let res2 = prf(&input[..], &oprf_key_bytes, info);
|
||||||
assert_eq!(res, res2);
|
assert_eq!(client_finalize_result.output, res2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -703,9 +827,15 @@ mod tests {
|
|||||||
let mut input = alloc::vec![0u8; 64];
|
let mut input = alloc::vec![0u8; 64];
|
||||||
rng.fill_bytes(&mut input);
|
rng.fill_bytes(&mut input);
|
||||||
let info = b"info";
|
let info = b"info";
|
||||||
let (client, alpha) =
|
let client_blind_result =
|
||||||
NonVerifiableClient::<Ristretto255Sha512>::blind(&input, &mut rng).unwrap();
|
NonVerifiableClient::<Ristretto255Sha512>::blind(&input, &mut rng).unwrap();
|
||||||
let res = client.finalize(EvaluationElement(alpha.0), info).unwrap();
|
let client_finalize_result = client_blind_result
|
||||||
|
.state
|
||||||
|
.finalize(
|
||||||
|
EvaluationElement(client_blind_result.message.0),
|
||||||
|
&Metadata(info.to_vec()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let dst = [
|
let dst = [
|
||||||
STR_HASH_TO_GROUP,
|
STR_HASH_TO_GROUP,
|
||||||
@@ -720,6 +850,6 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap()[0];
|
.unwrap()[0];
|
||||||
|
|
||||||
assert_eq!(res, res2);
|
assert_eq!(client_finalize_result.output, res2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user