diff --git a/.cargo/license.rs b/.cargo/license.rs new file mode 100644 index 0000000..3fa8d9f --- /dev/null +++ b/.cargo/license.rs @@ -0,0 +1,6 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under both the MIT license found in the +// LICENSE-MIT file in the root directory of this source tree and the Apache +// License, Version 2.0 found in the LICENSE-APACHE file in the root directory +// of this source tree. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3de270a..3e4e8d6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -128,18 +128,18 @@ jobs: args: --no-deps --document-private-items --features std,p256 - format: + rustfmt: name: cargo fmt runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v2 - - name: Install stable toolchain + - name: Install nightly toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: nightly override: true components: rustfmt @@ -148,3 +148,25 @@ jobs: with: command: fmt args: --all -- --check + + taplo: + name: Taplo + runs-on: ubuntu-latest + steps: + - name: Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/.crates.toml + ~/.cargo/.crates2.json + ~/.cargo/bin/taplo + key: taplo + + - name: Install Taplo + run: cargo install taplo-cli + + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Run Taplo + run: taplo fmt --check diff --git a/Cargo.toml b/Cargo.toml index cd59315..106744c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,26 +1,26 @@ [package] -name = "voprf" -version = "0.3.0" -description = "An implementation of a verifiable oblivious pseudorandom function (VOPRF)" authors = ["Kevin Lewi "] -repository = "https://github.com/novifinancial/voprf/" categories = ["no-std", "algorithms", "cryptography"] +description = "An implementation of a verifiable oblivious pseudorandom function (VOPRF)" +edition = "2018" keywords = ["oprf"] license = "MIT" -edition = "2018" +name = "voprf" readme = "README.md" +repository = "https://github.com/novifinancial/voprf/" resolver = "2" rust-version = "1.51.0" +version = "0.3.0" [features] -default = ["ristretto255_u64", "serde"] danger = [] -ristretto255_u64 = ["curve25519-dalek/u64_backend"] -ristretto255_u32 = ["curve25519-dalek/u32_backend"] -ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend"] -ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend"] -ristretto255_simd = ["curve25519-dalek/simd_backend"] +default = ["ristretto255_u64", "serde"] p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"] +ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend"] +ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend"] +ristretto255_simd = ["curve25519-dalek/simd_backend"] +ristretto255_u32 = ["curve25519-dalek/u32_backend"] +ristretto255_u64 = ["curve25519-dalek/u64_backend"] std = [] [dependencies] @@ -33,7 +33,10 @@ num-bigint = { version = "0.4", default-features = false, optional = true } num-integer = { version = "0.1", default-features = false, optional = true } num-traits = { version = "0.2", default-features = false, optional = true } once_cell = { version = "1", default-features = false, optional = true } -p256_ = { package = "p256", version = "0.9", default-features = false, features = ["arithmetic", "zeroize"], optional = true } +p256_ = { package = "p256", version = "0.9", default-features = false, features = [ + "arithmetic", + "zeroize", +], optional = true } rand_core = { version = "0.6", default-features = false } serde = { version = "1", default-features = false, optional = true } subtle = { version = "2.3", default-features = false } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..faa263a --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,8 @@ +format_code_in_doc_comments = true +format_strings = true +group_imports = "StdExternalCrate" +imports_granularity = "Module" +license_template_path = ".cargo/license.rs" +newline_style = "Unix" +unstable_features = true +wrap_comments = true diff --git a/src/group/expand.rs b/src/group/expand.rs index 26fc20e..ce7c4f0 100644 --- a/src/group/expand.rs +++ b/src/group/expand.rs @@ -5,15 +5,15 @@ // License, Version 2.0 found in the LICENSE-APACHE file in the root directory // of this source tree. +use core::ops::Add; + +use digest::{BlockInput, Digest}; +use generic_array::sequence::Concat; +use generic_array::typenum::{Unsigned, U1, U2}; +use generic_array::{ArrayLength, GenericArray}; + use crate::errors::InternalError; use crate::util::i2osp; -use core::ops::Add; -use digest::{BlockInput, Digest}; -use generic_array::{ - sequence::Concat, - typenum::{Unsigned, U1, U2}, - ArrayLength, GenericArray, -}; // Computes ceil(x / y) fn div_ceil(x: usize, y: usize) -> usize { @@ -79,10 +79,8 @@ where #[cfg(test)] mod tests { - use generic_array::{ - typenum::{U128, U32}, - GenericArray, - }; + use generic_array::typenum::{U128, U32}; + use generic_array::GenericArray; struct Params { msg: &'static str, diff --git a/src/group/mod.rs b/src/group/mod.rs index 683d912..72761bb 100644 --- a/src/group/mod.rs +++ b/src/group/mod.rs @@ -22,14 +22,17 @@ cfg_ristretto! { mod ristretto; } -use crate::errors::InternalError; use core::ops::{Add, Mul, Sub}; + use digest::{BlockInput, Digest}; -use generic_array::{typenum::U1, ArrayLength, GenericArray}; +use generic_array::typenum::U1; +use generic_array::{ArrayLength, GenericArray}; use rand_core::{CryptoRng, RngCore}; use subtle::ConstantTimeEq; use zeroize::Zeroize; +use crate::errors::InternalError; + /// A prime-order subgroup of a base field (EC, prime-order field ...). This /// subgroup is noted additively — as in the draft RFC — in this trait. pub trait Group: @@ -80,8 +83,8 @@ pub trait Group: scalar_bits: &GenericArray, ) -> Result; - /// Return a scalar from its fixed-length bytes representation. If the scalar - /// is zero, then return an error. + /// Return a scalar from its fixed-length bytes representation. If the + /// scalar is zero, then return an error. fn from_scalar_slice<'a>( scalar_bits: impl Into<&'a GenericArray>, ) -> Result { @@ -103,14 +106,14 @@ pub trait Group: type ElemLen: ArrayLength + 'static; /// Return an element from its fixed-length bytes representation. This is - /// the unchecked version, which does not check for deserializing the identity - /// element + /// the unchecked version, which does not check for deserializing the + /// identity element fn from_element_slice_unchecked( element_bits: &GenericArray, ) -> Result; - /// Return an element from its fixed-length bytes representation. If the element - /// is the identity element, return an error. + /// Return an element from its fixed-length bytes representation. If the + /// element is the identity element, return an error. fn from_element_slice<'a>( element_bits: impl Into<&'a GenericArray>, ) -> Result { diff --git a/src/group/p256.rs b/src/group/p256.rs index 8918eec..86ec5bd 100644 --- a/src/group/p256.rs +++ b/src/group/p256.rs @@ -5,18 +5,17 @@ // License, Version 2.0 found in the LICENSE-APACHE file in the root directory // of this source tree. -// Note: This group implementation of p256 is experimental for now, -// until hash-to-curve or crypto-bigint are fully supported. +// Note: This group implementation of p256 is experimental for now, until +// hash-to-curve or crypto-bigint are fully supported. #![allow( clippy::borrow_interior_mutable_const, clippy::declare_interior_mutable_const )] -use super::Group; -use crate::errors::InternalError; use core::ops::{Add, Div, Mul, Neg}; use core::str::FromStr; + use digest::{BlockInput, Digest}; use generic_array::typenum::{Unsigned, U1, U2, U32, U33, U48}; use generic_array::{ArrayLength, GenericArray}; @@ -32,6 +31,9 @@ use p256_::{AffinePoint, EncodedPoint, ProjectivePoint}; use rand_core::{CryptoRng, RngCore}; use subtle::{Choice, ConditionallySelectable}; +use super::Group; +use crate::errors::InternalError; + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.2 // `L: 48` pub type L = U48; @@ -109,7 +111,9 @@ impl Group for ProjectivePoint { >::Output: ArrayLength, { // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#[{%22num%22:211,%22gen%22:0},{%22name%22:%22XYZ%22},70,700,0] - // P-256 `n` is defined as `115792089210356248762697446949407573529996955224135760342 422259061068512044369` + // P-256 `n` is defined as + // `115792089210356248762697446949407573529996955224135760342 + // 422259061068512044369` const N: Lazy = Lazy::new(|| { BigInt::from_str( "115792089210356248762697446949407573529996955224135760342422259061068512044369", @@ -182,8 +186,8 @@ impl Group for ProjectivePoint { /// Corresponds to the hash_to_curve_simple_swu() function defined in /// /// -/// `cmov`, `mod_floor` and `modpow` needs to be made constant-time, which -/// will be supported after crypto-bigint is no longer experimental. See +/// `cmov`, `mod_floor` and `modpow` needs to be made constant-time, which will +/// be supported after crypto-bigint is no longer experimental. See /// for more context. #[allow(clippy::many_single_char_names)] @@ -435,9 +439,10 @@ fn hash_to_curve_simple_swu>( #[cfg(test)] mod tests { - use super::*; use generic_array::typenum::U96; + use super::*; + struct Params { msg: &'static str, px: &'static str, diff --git a/src/group/ristretto.rs b/src/group/ristretto.rs index 1b761fd..45edf2c 100644 --- a/src/group/ristretto.rs +++ b/src/group/ristretto.rs @@ -22,8 +22,8 @@ use generic_array::{ }; use rand_core::{CryptoRng, RngCore}; -// `cfg` here is only needed because of a bug in Rust's crate feature documentation. -// See: https://github.com/rust-lang/rust/issues/83428 +// `cfg` here is only needed because of a bug in Rust's crate feature documentation. See: +// https://github.com/rust-lang/rust/issues/83428 cfg_ristretto! { /// The implementation of such a subgroup for Ristretto impl Group for RistrettoPoint { diff --git a/src/group/tests.rs b/src/group/tests.rs index 49ae1ae..2d04156 100644 --- a/src/group/tests.rs +++ b/src/group/tests.rs @@ -10,8 +10,8 @@ use crate::errors::InternalError; use crate::group::Group; -// Test that the deserialization of a group element should throw an error -// if the identity element can be deserialized properly +// Test that the deserialization of a group element should throw an error if the +// identity element can be deserialized properly #[test] fn test_group_properties() -> Result<(), InternalError> { diff --git a/src/lib.rs b/src/lib.rs index bceb0ba..a65323d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,10 +14,10 @@ //! //! # 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 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. //! @@ -31,35 +31,35 @@ //! ## 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 +//! - [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. +//! 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. +//! 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. +//! [NonVerifiableServer::new()] to produce an instance of itself. This instance +//! must be persisted on the server and used for online client evaluations. //! //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; //! # type Hash = sha2::Sha512; +//! use rand::rngs::OsRng; +//! use rand::RngCore; //! use voprf::NonVerifiableServer; -//! use rand::{rngs::OsRng, RngCore}; //! //! let mut server_rng = OsRng; //! let server = NonVerifiableServer::::new(&mut server_rng) -//! .expect("Unable to construct server"); +//! .expect("Unable to construct server"); //! ``` //! //! ### Client Blinding @@ -73,14 +73,14 @@ //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; //! # type Hash = sha2::Sha512; +//! use rand::rngs::OsRng; +//! use rand::RngCore; //! use voprf::NonVerifiableClient; -//! use rand::{rngs::OsRng, RngCore}; //! //! let mut client_rng = OsRng; -//! let client_blind_result = NonVerifiableClient::::blind( -//! b"input".to_vec(), -//! &mut client_rng, -//! ).expect("Unable to construct client"); +//! let client_blind_result = +//! NonVerifiableClient::::blind(b"input".to_vec(), &mut client_rng) +//! .expect("Unable to construct client"); //! ``` //! //! ### Server Evaluation @@ -106,10 +106,9 @@ //! # let mut server_rng = OsRng; //! # let server = NonVerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); -//! let server_evaluate_result = server.evaluate( -//! &client_blind_result.message, -//! None, -//! ).expect("Unable to perform server evaluate"); +//! let server_evaluate_result = server +//! .evaluate(&client_blind_result.message, None) +//! .expect("Unable to perform server evaluate"); //! ``` //! //! ### Client Finalization @@ -137,79 +136,79 @@ //! # &client_blind_result.message, //! # None, //! # ).expect("Unable to perform server evaluate"); -//! let client_finalize_result = client_blind_result.state.finalize( -//! &server_evaluate_result.message, -//! None, -//! ).expect("Unable to perform client finalization"); +//! let client_finalize_result = client_blind_result +//! .state +//! .finalize(&server_evaluate_result.message, None) +//! .expect("Unable to perform client finalization"); //! //! println!("VOPRF output: {:?}", client_finalize_result.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 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. +//! 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. +//! [VerifiableServer::new()] to produce an instance of itself. This instance +//! must be persisted on the server and used for online client evaluations. //! //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; //! # type Hash = sha2::Sha512; +//! use rand::rngs::OsRng; +//! use rand::RngCore; //! use voprf::VerifiableServer; -//! use rand::{rngs::OsRng, RngCore}; //! //! let mut server_rng = OsRng; -//! let server = VerifiableServer::::new(&mut server_rng) -//! .expect("Unable to construct server"); +//! let server = +//! VerifiableServer::::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. +//! 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. +//! [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. //! //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; //! # type Hash = sha2::Sha512; +//! use rand::rngs::OsRng; +//! use rand::RngCore; //! use voprf::VerifiableClient; -//! use rand::{rngs::OsRng, RngCore}; //! //! let mut client_rng = OsRng; -//! let client_blind_result = VerifiableClient::::blind( -//! b"input".to_vec(), -//! &mut client_rng, -//! ).expect("Unable to construct client"); +//! let client_blind_result = +//! VerifiableClient::::blind(b"input".to_vec(), &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. +//! [VerifiableServer::evaluate] to produce a [VerifiableServerEvaluateResult], +//! which consists of an [EvaluationElement] to be sent to the client along with +//! a proof. //! //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; @@ -226,19 +225,17 @@ //! # let mut server_rng = OsRng; //! # let server = VerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); -//! let server_evaluate_result = server.evaluate( -//! &mut server_rng, -//! &client_blind_result.message, -//! None, -//! ).expect("Unable to perform server evaluate"); +//! let server_evaluate_result = server +//! .evaluate(&mut server_rng, &client_blind_result.message, 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 an output for the protocol. +//! [VerifiableServer::evaluate] (an [EvaluationElement]), the proof, and the +//! server's public key, and runs [VerifiableClient::finalize] to produce an +//! output for the protocol. //! //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; @@ -260,12 +257,15 @@ //! # &client_blind_result.message, //! # None, //! # ).expect("Unable to perform server evaluate"); -//! let client_finalize_result = client_blind_result.state.finalize( -//! &server_evaluate_result.message, -//! &server_evaluate_result.proof, -//! server.get_public_key(), -//! None, -//! ).expect("Unable to perform client finalization"); +//! let client_finalize_result = client_blind_result +//! .state +//! .finalize( +//! &server_evaluate_result.message, +//! &server_evaluate_result.proof, +//! server.get_public_key(), +//! None, +//! ) +//! .expect("Unable to perform client finalization"); //! //! println!("VOPRF output: {:?}", client_finalize_result.to_vec()); //! ``` @@ -278,15 +278,14 @@ //! //! ## 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. +//! 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: +//! First, the client produces 10 blindings, storing their resulting states and +//! messages: //! //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; @@ -298,19 +297,18 @@ //! let mut client_states = vec![]; //! let mut client_messages = vec![]; //! for _ in 0..10 { -//! let client_blind_result = VerifiableClient::::blind( -//! b"input".to_vec(), -//! &mut client_rng, -//! ).expect("Unable to construct client"); +//! let client_blind_result = +//! VerifiableClient::::blind(b"input".to_vec(), &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: +//! 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: //! //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; @@ -333,17 +331,15 @@ //! let mut server_rng = OsRng; //! # let server = VerifiableServer::::new(&mut server_rng) //! # .expect("Unable to construct server"); -//! let server_batch_evaluate_result = server.batch_evaluate( -//! &mut server_rng, -//! &client_messages, -//! None, -//! ).expect("Unable to perform server batch evaluate"); +//! let server_batch_evaluate_result = server +//! .batch_evaluate(&mut server_rng, &client_messages, 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, along with the server's proof, in order to produce -//! a vector of outputs if the proof verifies correctly. +//! Then, the client calls [VerifiableClient::batch_finalize] on the client +//! states saved from the first step, along with the messages returned by the +//! server, along with the server's proof, in order to produce a vector of +//! outputs if the proof verifies correctly. //! //! ``` //! # type Group = curve25519_dalek::ristretto::RistrettoPoint; @@ -377,7 +373,8 @@ //! &server_batch_evaluate_result.proof, //! server.get_public_key(), //! None, -//! ).expect("Unable to perform client batch finalization"); +//! ) +//! .expect("Unable to perform client batch finalization"); //! //! println!("VOPRF batch outputs: {:?}", client_batch_finalize_result); //! ``` @@ -386,34 +383,40 @@ //! //! 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. +//! 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. //! -//! A custom metadata can be specified, for example, by: `Some(b"custom metadata")`. +//! A custom metadata can be specified, for example, by: +//! `Some(b"custom metadata")`. //! //! # Features //! -//! - The `p256` feature enables using p256 as the underlying group for the [Group](group::Group) choice. -//! Note that this is currently an experimental feature ⚠️, and is not yet ready for production use. +//! - The `p256` feature enables using p256 as the underlying group for the +//! [Group](group::Group) choice. Note that this is currently an experimental +//! feature ⚠️, and is not yet ready for production use. //! -//! - The `serde` feature, enabled by default, provides convenience functions for serializing and deserializing with -//! [serde](https://serde.rs/). +//! - The `serde` feature, enabled by default, provides convenience functions +//! for serializing and deserializing with [serde](https://serde.rs/). //! -//! - The `danger` feature, disabled by default, exposes functions for setting and getting -//! internal values not available in the default API. These functions are intended for use in -//! by higher-level cryptographic protocols that need access to these raw values and are able to -//! perform the necessary validations on them (such as being valid group elements). +//! - The `danger` feature, disabled by default, exposes functions for setting +//! and getting internal values not available in the default API. These +//! functions are intended for use in by higher-level cryptographic protocols +//! that need access to these raw values and are able to perform the necessary +//! validations on them (such as being valid group elements). //! -//! - The 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 `ristretto255_u64` feature is included as the default. -//! Other features are mapped as `ristretto255_u32`, `ristretto255_fiat_u64` and `ristretto255_fiat_u32`. +//! - The 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 `ristretto255_u64` feature is included as the default. Other +//! features are mapped as `ristretto255_u32`, `ristretto255_fiat_u64` and +//! `ristretto255_fiat_u32`. //! -//! - The `ristretto255_simd` feature is re-exported from -//! [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) and enables parallel formulas, -//! using either AVX2 or AVX512-IFMA. This will automatically enable the `ristretto255_u64` feature and requires Rust nightly. +//! - The `ristretto255_simd` feature is re-exported from [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) +//! and enables parallel formulas, using either AVX2 or AVX512-IFMA. This will +//! automatically enable the `ristretto255_u64` feature and requires Rust +//! nightly. #![deny(unsafe_code)] #![no_std] diff --git a/src/serialization.rs b/src/serialization.rs index a78d479..1e0be7d 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -5,22 +5,22 @@ // License, Version 2.0 found in the LICENSE-APACHE file in the root directory // of this source tree. -//! Handles the serialization of each of the components used -//! in the VOPRF protocol +//! Handles the serialization of each of the components used in the VOPRF +//! protocol -use crate::{ - errors::InternalError, - group::Group, - voprf::{ - BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableServer, Proof, - VerifiableClient, VerifiableServer, - }, -}; use alloc::vec::Vec; use core::marker::PhantomData; + use digest::{BlockInput, Digest}; use generic_array::typenum::Unsigned; +use crate::errors::InternalError; +use crate::group::Group; +use crate::voprf::{ + BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableServer, Proof, + VerifiableClient, VerifiableServer, +}; + ////////////////////////////////////////////////////////// // Serialization and Deserialization for High-Level API // // ==================================================== // diff --git a/src/tests/mock_rng.rs b/src/tests/mock_rng.rs index fc80938..3ccaee8 100644 --- a/src/tests/mock_rng.rs +++ b/src/tests/mock_rng.rs @@ -7,21 +7,20 @@ use alloc::vec::Vec; use core::cmp::min; + use rand_core::{CryptoRng, Error, RngCore}; /// A simple implementation of `RngCore` for testing purposes. /// /// This generates a cyclic sequence (i.e. cycles over an initial buffer) -/// -/// #[derive(Debug, Clone)] pub struct CycleRng { v: Vec, } impl CycleRng { - /// Create a `CycleRng`, yielding a sequence starting with - /// `initial` and looping thereafter + /// Create a `CycleRng`, yielding a sequence starting with `initial` and + /// looping thereafter pub fn new(initial: Vec) -> Self { CycleRng { v: initial } } diff --git a/src/tests/voprf_test_vectors.rs b/src/tests/voprf_test_vectors.rs index 31b5757..2c065ac 100644 --- a/src/tests/voprf_test_vectors.rs +++ b/src/tests/voprf_test_vectors.rs @@ -5,22 +5,23 @@ // License, Version 2.0 found in the LICENSE-APACHE file in the root directory // of this source tree. -use crate::{ - errors::InternalError, - group::Group, - tests::{mock_rng::CycleRng, parser::*}, - voprf::{ - BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableServer, Proof, - VerifiableClient, VerifiableServer, - }, -}; use alloc::string::{String, ToString}; use alloc::vec; use alloc::vec::Vec; + use digest::{BlockInput, Digest}; use generic_array::GenericArray; use json::JsonValue; +use crate::errors::InternalError; +use crate::group::Group; +use crate::tests::mock_rng::CycleRng; +use crate::tests::parser::*; +use crate::voprf::{ + BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableServer, Proof, + VerifiableClient, VerifiableServer, +}; + #[derive(Debug)] struct VOPRFTestVectorParameters { seed: Vec, diff --git a/src/util.rs b/src/util.rs index 625d06a..610b1e9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -7,9 +7,12 @@ //! Helper functions -use crate::errors::InternalError; use core::array::IntoIter; -use generic_array::{typenum::U0, ArrayLength, GenericArray}; + +use generic_array::typenum::U0; +use generic_array::{ArrayLength, GenericArray}; + +use crate::errors::InternalError; // Corresponds to the I2OSP() function from RFC8017 pub(crate) fn i2osp>( @@ -100,8 +103,9 @@ macro_rules! chain_skip { }; } -/// The purpose of this macro is to simplify [`concat`](alloc::slice::Concat::concat)ing -/// slices into an [`Iterator`] to avoid allocation +/// The purpose of this macro is to simplify +/// [`concat`](alloc::slice::Concat::concat)ing slices into an [`Iterator`] to +/// avoid allocation macro_rules! chain { ( $var:ident, @@ -142,13 +146,15 @@ macro_rules! cfg_ristretto { #[cfg(test)] mod unit_tests { + use generic_array::typenum::{U1, U2}; + use proptest::collection::vec; + use proptest::prelude::*; + use super::*; use crate::voprf::{ BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableServer, Proof, VerifiableClient, VerifiableServer, }; - use generic_array::typenum::{U1, U2}; - use proptest::{collection::vec, prelude::*}; // Test the error condition for I2OSP #[test] diff --git a/src/voprf.rs b/src/voprf.rs index 02ac827..1c8c81f 100644 --- a/src/voprf.rs +++ b/src/voprf.rs @@ -7,24 +7,22 @@ //! Contains the main VOPRF API -use crate::{ - errors::InternalError, - group::Group, - util::{i2osp, serialize, serialize_owned}, -}; use alloc::vec::Vec; use core::convert::TryInto; use core::marker::PhantomData; + use derive_where::DeriveWhere; use digest::{BlockInput, Digest}; use generic_array::sequence::Concat; -use generic_array::{ - typenum::{U1, U11, U2}, - GenericArray, -}; +use generic_array::typenum::{U1, U11, U2}; +use generic_array::GenericArray; use rand_core::{CryptoRng, RngCore}; use subtle::ConstantTimeEq; +use crate::errors::InternalError; +use crate::group::Group; +use crate::util::{i2osp, serialize, serialize_owned}; + /////////////// // Constants // // ========= // @@ -39,8 +37,7 @@ static STR_COMPOSITE: [u8; 10] = *b"Composite-"; static STR_CHALLENGE: [u8; 10] = *b"Challenge-"; static STR_VOPRF: [u8; 8] = *b"VOPRF08-"; -/// Determines the mode of operation (either base mode or -/// verifiable mode) +/// Determines the mode of operation (either base mode or verifiable mode) #[derive(Clone, Copy)] enum Mode { Base = 0, @@ -52,9 +49,8 @@ enum Mode { // ====================== // //////////////////////////// -/// A client which engages with a [NonVerifiableServer] -/// in base mode, meaning that the OPRF outputs are not -/// verifiable. +/// A client which engages with a [NonVerifiableServer] in base mode, meaning +/// that the OPRF outputs are not verifiable. #[derive(DeriveWhere)] #[derive_where(Clone, Zeroize(drop))] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Scalar)] @@ -67,9 +63,8 @@ pub struct NonVerifiableClient { impl_serialize_and_deserialize_for!(NonVerifiableClient); -/// A client which engages with a [VerifiableServer] -/// in verifiable mode, meaning that the OPRF outputs -/// can be checked against a server public key. +/// A client which engages with a [VerifiableServer] in verifiable mode, meaning +/// that the OPRF outputs can be checked against a server public key. #[derive(DeriveWhere)] #[derive_where(Clone, Zeroize(drop))] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G, G::Scalar)] @@ -83,9 +78,8 @@ pub struct VerifiableClient { impl_serialize_and_deserialize_for!(VerifiableClient); -/// A server which engages with a [NonVerifiableClient] -/// in base mode, meaning that the OPRF outputs are not -/// verifiable. +/// A server which engages with a [NonVerifiableClient] in base mode, meaning +/// that the OPRF outputs are not verifiable. #[derive(DeriveWhere)] #[derive_where(Clone, Zeroize(drop))] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Scalar)] @@ -97,9 +91,8 @@ pub struct NonVerifiableServer { impl_serialize_and_deserialize_for!(NonVerifiableServer); -/// A server which engages with a [VerifiableClient] -/// in verifiable mode, meaning that the OPRF outputs -/// can be checked against a server public key. +/// A server which engages with a [VerifiableClient] in verifiable mode, meaning +/// that the OPRF outputs can be checked against a server public key. #[derive(DeriveWhere)] #[derive_where(Clone, Zeroize(drop))] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G, G::Scalar)] @@ -112,8 +105,8 @@ pub struct VerifiableServer { impl_serialize_and_deserialize_for!(VerifiableServer); -/// A proof produced by a [VerifiableServer] that -/// the OPRF output matches against a server public key. +/// A proof produced by a [VerifiableServer] that the OPRF output matches +/// against a server public key. #[derive(DeriveWhere)] #[derive_where(Clone, Zeroize(drop))] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Scalar)] @@ -126,8 +119,8 @@ pub struct Proof { impl_serialize_and_deserialize_for!(Proof); -/// The first client message sent from a client (either verifiable or not) -/// to a server (either verifiable or not). +/// The first client message sent from a client (either verifiable or not) to a +/// server (either verifiable or not). #[derive(DeriveWhere)] #[derive_where(Clone, Zeroize(drop))] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G)] @@ -139,9 +132,8 @@ pub struct BlindedElement { impl_serialize_and_deserialize_for!(BlindedElement); -/// The server's response to the [BlindedElement] message from -/// a client (either verifiable or not) -/// to a server (either verifiable or not). +/// The server's response to the [BlindedElement] message from a client (either +/// verifiable or not) to a server (either verifiable or not). #[derive(DeriveWhere)] #[derive_where(Clone, Zeroize(drop))] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G)] @@ -159,7 +151,8 @@ impl_serialize_and_deserialize_for!(EvaluationElement); ///////////////////////// impl NonVerifiableClient { - /// Computes the first step for the multiplicative blinding version of DH-OPRF. + /// Computes the first step for the multiplicative blinding version of + /// DH-OPRF. pub fn blind( input: Vec, blinding_factor_rng: &mut R, @@ -179,13 +172,14 @@ impl NonVerifiableClient { } #[cfg(any(feature = "danger", test))] - /// Computes the first step for the multiplicative blinding version of DH-OPRF, - /// taking a blinding factor scalar as input instead of sampling from an RNG. + /// Computes the first step for the multiplicative blinding version of + /// DH-OPRF, taking a blinding factor scalar as input instead of sampling + /// from an RNG. /// /// # Caution /// - /// This should be used with caution, since - /// it does not perform any checks on the validity of the blinding factor! + /// This should be used with caution, since it does not perform any checks + /// on the validity of the blinding factor! pub fn deterministic_blind_unchecked( input: Vec, blind: G::Scalar, @@ -204,8 +198,8 @@ impl NonVerifiableClient { }) } - /// Computes the third step for the multiplicative blinding version of DH-OPRF, in which - /// the client unblinds the server's message. + /// Computes the third step for the multiplicative blinding version of + /// DH-OPRF, in which the client unblinds the server's message. pub fn finalize( &self, evaluation_element: &EvaluationElement, @@ -238,7 +232,8 @@ impl NonVerifiableClient { } impl VerifiableClient { - /// Computes the first step for the multiplicative blinding version of DH-OPRF. + /// Computes the first step for the multiplicative blinding version of + /// DH-OPRF. pub fn blind( input: Vec, blinding_factor_rng: &mut R, @@ -260,13 +255,14 @@ impl VerifiableClient { } #[cfg(any(feature = "danger", test))] - /// Computes the first step for the multiplicative blinding version of DH-OPRF, - /// taking a blinding factor scalar as input instead of sampling from an RNG. + /// Computes the first step for the multiplicative blinding version of + /// DH-OPRF, taking a blinding factor scalar as input instead of sampling + /// from an RNG. /// /// # Caution /// - /// This should be used with caution, since - /// it does not perform any checks on the validity of the blinding factor! + /// This should be used with caution, since it does not perform any checks + /// on the validity of the blinding factor! pub fn deterministic_blind_unchecked( input: Vec, blind: G::Scalar, @@ -287,8 +283,8 @@ impl VerifiableClient { }) } - /// Computes the third step for the multiplicative blinding version of DH-OPRF, in which - /// the client unblinds the server's message. + /// Computes the third step for the multiplicative blinding version of + /// DH-OPRF, in which the client unblinds the server's message. pub fn finalize( &self, evaluation_element: &EvaluationElement, @@ -306,7 +302,8 @@ impl VerifiableClient { Ok(batch_result[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 pub fn batch_finalize<'a, IC, IM>( clients: &'a IC, messages: &'a IM, @@ -400,8 +397,8 @@ impl NonVerifiableServer { Self::new_from_seed(&seed) } - /// Produces a new instance of a [NonVerifiableServer] using a supplied set of bytes to - /// represent the server's private key + /// Produces a new instance of a [NonVerifiableServer] using a supplied set + /// of bytes to represent the server's private key pub fn new_with_key(private_key_bytes: &[u8]) -> Result { let sk = G::from_scalar_slice(private_key_bytes)?; Ok(Self { @@ -410,8 +407,8 @@ impl NonVerifiableServer { }) } - /// Produces a new instance of a [NonVerifiableServer] using a supplied set of bytes which - /// are used as a seed to derive the server's private key. + /// Produces a new instance of a [NonVerifiableServer] using a supplied set + /// of bytes which are used as a seed to derive the server's private key. /// /// Corresponds to DeriveKeyPair() function from the VOPRF specification. pub fn new_from_seed(seed: &[u8]) -> Result { @@ -430,8 +427,9 @@ impl NonVerifiableServer { self.sk } - /// Computes the second step for the multiplicative blinding version of DH-OPRF. This - /// message is sent from the server (who holds the OPRF key) to the client. + /// Computes the second step for the multiplicative blinding version of + /// DH-OPRF. This message is sent from the server (who holds the OPRF key) + /// to the client. pub fn evaluate( &self, blinded_element: &BlindedElement, @@ -465,8 +463,8 @@ impl VerifiableServer { Self::new_from_seed(&seed) } - /// Produces a new instance of a [VerifiableServer] using a supplied set of bytes to - /// represent the server's private key + /// Produces a new instance of a [VerifiableServer] using a supplied set of + /// bytes to represent the server's private key pub fn new_with_key(key: &[u8]) -> Result { let sk = G::from_scalar_slice(key)?; let pk = G::base_point() * &sk; @@ -477,8 +475,8 @@ impl VerifiableServer { }) } - /// Produces a new instance of a [VerifiableServer] using a supplied set of bytes which - /// are used as a seed to derive the server's private key. + /// Produces a new instance of a [VerifiableServer] using a supplied set of + /// bytes which are used as a seed to derive the server's private key. /// /// Corresponds to DeriveKeyPair() function from the VOPRF specification. pub fn new_from_seed(seed: &[u8]) -> Result { @@ -499,8 +497,9 @@ impl VerifiableServer { self.sk } - /// Computes the second step for the multiplicative blinding version of DH-OPRF. This - /// message is sent from the server (who holds the OPRF key) to the client. + /// Computes the second step for the multiplicative blinding version of + /// DH-OPRF. This message is sent from the server (who holds the OPRF key) + /// to the client. pub fn evaluate( &self, rng: &mut R, @@ -518,7 +517,8 @@ impl VerifiableServer { }) } - /// 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] pub fn batch_evaluate<'a, R: RngCore + CryptoRng, I>( &self, rng: &mut R, @@ -641,8 +641,8 @@ impl BlindedElement { /// /// # Caution /// - /// This should be used with caution, since - /// it does not perform any checks on the validity of the value itself! + /// This should be used with caution, since it does not perform any checks + /// on the validity of the value itself! pub fn from_value_unchecked(value: G) -> Self { Self { value, @@ -671,8 +671,8 @@ impl EvaluationElement { /// /// # Caution /// - /// This should be used with caution, since - /// it does not perform any checks on the validity of the value itself! + /// This should be used with caution, since it does not perform any checks + /// on the validity of the value itself! pub fn from_value_unchecked(value: G) -> Self { Self { value, @@ -699,8 +699,9 @@ fn blind( Ok((blind, blinded_element)) } -// Inner function for blind that assumes that the blinding factor has already been chosen, -// and therefore takes it as input. Does not check if the blinding factor is non-zero. +// Inner function for blind that assumes that the blinding factor has already +// been chosen, and therefore takes it as input. Does not check if the blinding +// factor is non-zero. fn deterministic_blind_unchecked( input: &[u8], blind: &G::Scalar, @@ -918,13 +919,15 @@ fn get_context_string(mode: Mode) -> Result, Int #[cfg(test)] mod tests { - use super::*; - use crate::group::Group; use alloc::vec; + use generic_array::GenericArray; use rand::rngs::OsRng; use zeroize::Zeroize; + use super::*; + use crate::group::Group; + fn prf( input: &[u8], key: G::Scalar, diff --git a/taplo.toml b/taplo.toml new file mode 100644 index 0000000..7653be7 --- /dev/null +++ b/taplo.toml @@ -0,0 +1,3 @@ +[formatting] +reorder_keys = true +allowed_blank_lines = 1