Configure Rustfmt and Taplo (#38)

* Configure rustfmt

* Add Taplo configuration and run in CI
This commit is contained in:
daxpedda
2021-12-22 19:17:03 -05:00
committed by GitHub
parent 4700d4b725
commit 140f9e063d
16 changed files with 319 additions and 259 deletions
+6
View File
@@ -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.
+25 -3
View File
@@ -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
+15 -12
View File
@@ -1,26 +1,26 @@
[package]
name = "voprf"
version = "0.3.0"
description = "An implementation of a verifiable oblivious pseudorandom function (VOPRF)"
authors = ["Kevin Lewi <[email protected]>"]
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 }
+8
View File
@@ -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
+9 -11
View File
@@ -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,
+11 -8
View File
@@ -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<u8, Self::ScalarLen>,
) -> Result<Self::Scalar, InternalError>;
/// 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<u8, Self::ScalarLen>>,
) -> Result<Self::Scalar, InternalError> {
@@ -103,14 +106,14 @@ pub trait Group:
type ElemLen: ArrayLength<u8> + '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<u8, Self::ElemLen>,
) -> Result<Self, InternalError>;
/// 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<u8, Self::ElemLen>>,
) -> Result<Self, InternalError> {
+13 -8
View File
@@ -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 {
<D as Add<U1>>::Output: ArrayLength<u8>,
{
// 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<BigInt> = 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
/// <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-F.2>
///
/// `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
/// <https://github.com/novifinancial/voprf/issues/13> for more context.
#[allow(clippy::many_single_char_names)]
@@ -435,9 +439,10 @@ fn hash_to_curve_simple_swu<N: ArrayLength<u8>>(
#[cfg(test)]
mod tests {
use super::*;
use generic_array::typenum::U96;
use super::*;
struct Params {
msg: &'static str,
px: &'static str,
+2 -2
View File
@@ -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 {
+2 -2
View File
@@ -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> {
+121 -118
View File
@@ -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::<Group, Hash>::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::<Group, Hash>::blind(
//! b"input".to_vec(),
//! &mut client_rng,
//! ).expect("Unable to construct client");
//! let client_blind_result =
//! NonVerifiableClient::<Group, Hash>::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::<Group, Hash>::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::<Group, Hash>::new(&mut server_rng)
//! .expect("Unable to construct server");
//! let server =
//! VerifiableServer::<Group, Hash>::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::<Group, Hash>::blind(
//! b"input".to_vec(),
//! &mut client_rng,
//! ).expect("Unable to construct client");
//! let client_blind_result =
//! VerifiableClient::<Group, Hash>::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::<Group, Hash>::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::<Group, Hash>::blind(
//! b"input".to_vec(),
//! &mut client_rng,
//! ).expect("Unable to construct client");
//! let client_blind_result =
//! VerifiableClient::<Group, Hash>::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::<Group, Hash>::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]
+10 -10
View File
@@ -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 //
// ==================================================== //
+3 -4
View File
@@ -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<u8>,
}
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<u8>) -> Self {
CycleRng { v: initial }
}
+10 -9
View File
@@ -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<u8>,
+12 -6
View File
@@ -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<L: ArrayLength<u8>>(
@@ -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]
+69 -66
View File
@@ -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<G: Group, H: BlockInput + Digest> {
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<G: Group, H: BlockInput + Digest> {
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<G: Group, H: BlockInput + Digest> {
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<G: Group, H: BlockInput + Digest> {
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<G: Group, H: BlockInput + Digest> {
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<G: Group, H: BlockInput + Digest> {
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<G: Group, H: BlockInput + Digest> NonVerifiableClient<G, H> {
/// 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<R: RngCore + CryptoRng>(
input: Vec<u8>,
blinding_factor_rng: &mut R,
@@ -179,13 +172,14 @@ impl<G: Group, H: BlockInput + Digest> NonVerifiableClient<G, H> {
}
#[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<u8>,
blind: G::Scalar,
@@ -204,8 +198,8 @@ impl<G: Group, H: BlockInput + Digest> NonVerifiableClient<G, H> {
})
}
/// 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<G, H>,
@@ -238,7 +232,8 @@ impl<G: Group, H: BlockInput + Digest> NonVerifiableClient<G, H> {
}
impl<G: Group, H: BlockInput + Digest> VerifiableClient<G, H> {
/// 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<R: RngCore + CryptoRng>(
input: Vec<u8>,
blinding_factor_rng: &mut R,
@@ -260,13 +255,14 @@ impl<G: Group, H: BlockInput + Digest> VerifiableClient<G, H> {
}
#[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<u8>,
blind: G::Scalar,
@@ -287,8 +283,8 @@ impl<G: Group, H: BlockInput + Digest> VerifiableClient<G, H> {
})
}
/// 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<G, H>,
@@ -306,7 +302,8 @@ impl<G: Group, H: BlockInput + Digest> VerifiableClient<G, H> {
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<G: Group, H: BlockInput + Digest> NonVerifiableServer<G, H> {
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<Self, InternalError> {
let sk = G::from_scalar_slice(private_key_bytes)?;
Ok(Self {
@@ -410,8 +407,8 @@ impl<G: Group, H: BlockInput + Digest> NonVerifiableServer<G, H> {
})
}
/// 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<Self, InternalError> {
@@ -430,8 +427,9 @@ impl<G: Group, H: BlockInput + Digest> NonVerifiableServer<G, H> {
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<G, H>,
@@ -465,8 +463,8 @@ impl<G: Group, H: BlockInput + Digest> VerifiableServer<G, H> {
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<Self, InternalError> {
let sk = G::from_scalar_slice(key)?;
let pk = G::base_point() * &sk;
@@ -477,8 +475,8 @@ impl<G: Group, H: BlockInput + Digest> VerifiableServer<G, H> {
})
}
/// 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<Self, InternalError> {
@@ -499,8 +497,9 @@ impl<G: Group, H: BlockInput + Digest> VerifiableServer<G, H> {
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<R: RngCore + CryptoRng>(
&self,
rng: &mut R,
@@ -518,7 +517,8 @@ impl<G: Group, H: BlockInput + Digest> VerifiableServer<G, H> {
})
}
/// 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<G: Group, H: BlockInput + Digest> BlindedElement<G, H> {
///
/// # 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<G: Group, H: BlockInput + Digest> EvaluationElement<G, H> {
///
/// # 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<G: Group, H: BlockInput + Digest, R: RngCore + CryptoRng>(
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<G: Group, H: BlockInput + Digest>(
input: &[u8],
blind: &G::Scalar,
@@ -918,13 +919,15 @@ fn get_context_string<G: Group>(mode: Mode) -> Result<GenericArray<u8, U11>, 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<G: Group, H: BlockInput + Digest>(
input: &[u8],
key: G::Scalar,
+3
View File
@@ -0,0 +1,3 @@
[formatting]
reorder_keys = true
allowed_blank_lines = 1