From 10069615642ef0ea3c40543738bcc4e1c7d7331f Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 11:29:13 +0200 Subject: [PATCH 01/10] Base module docs --- README.md | 134 +++++++++++++++++++++++++++++++++++++++++++----- src/ietf.rs | 35 ++++++++++++- src/lib.rs | 127 +++++++++++++++++++++++---------------------- src/pedersen.rs | 36 ++++++++++++- src/ring.rs | 78 +++++++++++++++++++++++++++- 5 files changed, 330 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 4eeb12c..58f9416 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,35 @@ into its signature. It leverages the [Arkworks](https://github.com/arkworks-rs) framework and supports customization of scheme parameters. -### Supported Schemes +## What is a VRF? + + A Verifiable Random Function (VRF) is a cryptographic primitive that maps inputs + to verifiable pseudorandom outputs. Key properties include: + + - **Uniqueness**: For a given input and private key, there is exactly one valid output + - **Verifiability**: Anyone with the public key can verify that an output is correct + - **Pseudorandomness**: Without the private key, outputs appear random and unpredictable + - **Collision resistance**: Finding inputs that map to the same output is computationally infeasible + +## Supported Schemes - **IETF VRF**: Complies with ECVRF described in [RFC9381](https://datatracker.ietf.org/doc/rfc9381). + This is a standardized VRF implementation suitable for most applications requiring + verifiable randomness. + - **Pedersen VRF**: Described in [BCHSV23](https://eprint.iacr.org/2023/002). -- **Ring VRF**: A zero-knowledge-based inspired by [BCHSV23](https://eprint.iacr.org/2023/002). + Extends the basic VRF with key-hiding properties using Pedersen commitments, + +- **Ring VRF**: A zero-knowledge-based scheme inspired by [BCHSV23](https://eprint.iacr.org/2023/002). + Provides signer anonymity within a set of public keys (a "ring"), allowing + verification that a ring member created the proof without revealing which specific member. -### Schemes Specifications +### Specifications -- [VRF Schemes Details](https://github.com/davxy/bandersnatch-vrf-spec) -- [Ring VRF ZK Proof](https://github.com/davxy/ring-proof-spec) +- [VRF Schemes](https://github.com/davxy/bandersnatch-vrf-spec) +- [Ring Proof](https://github.com/davxy/ring-proof-spec) -### Built-In suites +## Built-In suites The library conditionally includes the following pre-configured suites (see features section): @@ -29,68 +46,159 @@ The library conditionally includes the following pre-configured suites (see feat - **JubJub** (_Edwards curve on BLS12-381_): Supports IETF, Pedersen, and Ring VRF. - **Baby-JubJub** (_Edwards curve on BN254_): Supports IETF, Pedersen, and Ring VRF. -### Basic Usage +## Basic Usage ```rust use ark_vrf::suites::bandersnatch::*; + +// Create a secret key from a seed let secret = Secret::from_seed(b"example seed"); + +// Derive the corresponding public key let public = secret.public(); + +// Create an input by hashing date to a curve point let input = Input::new(b"example input"); + +// Compute the VRF output (gamma point) let output = secret.output(input); + +// Optional additional data that can be bound to the proof let aux_data = b"optional aux data"; ``` -#### IETF-VRF + +The VRF output can be hashed to obtain a pseudorandom byte string: + +```rust +// Get a deterministic hash from the VRF output point +let hash_bytes = output.hash(); +``` + +### IETF-VRF + +The IETF VRF scheme follows [RFC-9381](https://datatracker.ietf.org/doc/rfc9381) +and provides a standardized approach to verifiable random functions. _Prove_ ```rust use ark_vrf::ietf::Prover; + +// Generate a proof that binds the input, output, and auxiliary data let proof = secret.prove(input, output, aux_data); + +// The proof can be serialized for transmission +let serialized_proof = proof.to_bytes(); ``` _Verify_ ```rust use ark_vrf::ietf::Verifier; + +// Verify the proof against the public key let result = public.verify(input, output, aux_data, &proof); +assert!(result.is_ok()); + +// Verification will fail if any parameter is modified +let tampered_output = secret.output(Input::new(b"different input").unwrap()); +assert!(public.verify(input, tampered_output, aux_data, &proof).is_err()); +``` + +### Pedersen-VRF + +The Pedersen VRF extends the IETF scheme with key-hiding properties using Pedersen commitments. + +_Prove_ +```rust +use ark_vrf::pedersen::Prover; + +// Generate a proof with a blinding factor +let (proof, blinding_factor) = secret.prove(input, output, aux_data); + +// The proof includes a commitment to the public key +let key_commitment = proof.key_commitment(); ``` -#### Ring-VRF +_Verify_ +```rust +use ark_vrf::pedersen::Verifier; + +// Verify without knowing which specific public key was used. +// Verifiers that the secret key used to generate `output` is the same as +// the secret key used to generate `proof.key_commitment()`. +let result = Public::verify(input, output, aux_data, &proof); +assert!(result.is_ok()); + +assert_eq!( + proof.key_commitment(), + (public.0 + S::BLINDING_BASE * blinding_factor).into() +); +``` +### Ring-VRF + +The Ring VRF provides anonymity within a set of public keys using zero-knowledge proofs. + _Ring construction_ ```rust const RING_SIZE: usize = 100; let prover_key_index = 3; + // Construct an example ring with dummy keys -let mut ring = (0..RING_SIZE).map(|i| Secret::from_seed(&i.to_le_bytes()).public().0).collect(); +let mut ring = (0..RING_SIZE) + .map(|i| Secret::from_seed(&i.to_le_bytes()).public().0) + .collect::>(); + // Patch the ring with the public key of the prover ring[prover_key_index] = public.0; + // Any key can be replaced with the padding point ring[0] = RingProofParams::padding_point(); -``` -_Ring parameters construction_ -```rust +// Create parameters for the ring proof system. +// These parameters are reusable across multiple proofs let params = RingProofParams::from_seed(RING_SIZE, b"example seed"); ``` _Prove_ ```rust use ark_vrf::ring::Prover; + +// Create a prover key specific to this ring let prover_key = params.prover_key(&ring); + +// Create a prover instance for the specific position in the ring let prover = params.prover(prover_key, prover_key_index); + +// Generate a zero-knowledge proof that: +// 1. The prover knows a secret key for one of the public keys in the ring +// 2. That secret key was used to generate the VRF output let proof = secret.prove(input, output, aux_data, &prover); ``` _Verify_ ```rust use ark_vrf::ring::Verifier; + +// Create a verifier key for this ring let verifier_key = params.verifier_key(&ring); + +// Create a verifier instance let verifier = params.verifier(verifier_key); + +// Verify the proof - this confirms that: +// 1. The proof was created by someone who knows a secret key in the ring +// 2. The VRF output is correct for the given input +// But it does NOT reveal which ring member created the proof let result = Public::verify(input, output, aux_data, &proof, &verifier); ``` _Verifier key from commitment_ ```rust +// For efficiency, a commitment to the ring can be shared let ring_commitment = params.verifier_key().commitment(); + +// A verifier can reconstruct the verifier key from just the commitment +// without needing the full ring of public keys let verifier_key = params.verifier_key_from_commitment(ring_commitment); ``` diff --git a/src/ietf.rs b/src/ietf.rs index 4baa45f..3ca1307 100644 --- a/src/ietf.rs +++ b/src/ietf.rs @@ -1,8 +1,39 @@ -//! EC-VRF as specified by [RFC-9381](https://datatracker.ietf.org/doc/rfc9381). +//! ### IETF-VRF //! -//! The implementation extends RFC9381 to allow to sign additional user data together +//! The IETF VRF scheme follows [RFC-9381](https://datatracker.ietf.org/doc/rfc9381) +//! and provides a standardized approach to verifiable random functions. +//! +//! The implementation extends RFC-9381 to allow to sign additional user data together //! with the VRF input. Refer to for //! specification extension details. +//! +//! ## Usage +//! +//! ### Prove +//! +//! ```rust,ignore +//! use ark_vrf::ietf::Prover; +//! +//! // Generate a proof that binds the input, output, and auxiliary data +//! let proof = secret.prove(input, output, aux_data); +//! +//! // The proof can be serialized for transmission +//! let serialized_proof = proof.serialize_compressed(); +//! ``` +//! +//! ### Verify +//! +//! ```rust,ignore +//! use ark_vrf::ietf::Verifier; +//! +//! // Verify the proof against the public key +//! let result = public.verify(input, output, aux_data, &proof); +//! assert!(result.is_ok()); +//! +//! // Verification will fail if any parameter is modified +//! let tampered_output = secret.output(Input::new(b"different input").unwrap()); +//! assert!(public.verify(input, tampered_output, aux_data, &proof).is_err()); +//! ``` use super::*; diff --git a/src/lib.rs b/src/lib.rs index 470bb69..a4fc0cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,18 +8,35 @@ //! It leverages the [Arkworks](https://github.com/arkworks-rs) framework and //! supports customization of scheme parameters. //! -//! ### Supported Schemes +//! ## What is a VRF? +//! +//! A Verifiable Random Function (VRF) is a cryptographic primitive that maps inputs +//! to verifiable pseudorandom outputs. Key properties include: +//! +//! - **Uniqueness**: For a given input and private key, there is exactly one valid output +//! - **Verifiability**: Anyone with the public key can verify that an output is correct +//! - **Pseudorandomness**: Without the private key, outputs appear random and unpredictable +//! - **Collision resistance**: Finding inputs that map to the same output is computationally infeasible +//! +//! ## Supported Schemes //! //! - **IETF VRF**: Complies with ECVRF described in [RFC9381](https://datatracker.ietf.org/doc/rfc9381). +//! This is a standardized VRF implementation suitable for most applications requiring +//! verifiable randomness. +//! //! - **Pedersen VRF**: Described in [BCHSV23](https://eprint.iacr.org/2023/002). -//! - **Ring VRF**: A zero-knowledge-based inspired by [BCHSV23](https://eprint.iacr.org/2023/002). +//! Extends the basic VRF with key-hiding properties using Pedersen commitments, +//! +//! - **Ring VRF**: A zero-knowledge-based scheme inspired by [BCHSV23](https://eprint.iacr.org/2023/002). +//! Provides signer anonymity within a set of public keys (a "ring"), allowing +//! verification that a ring member created the proof without revealing which specific member. //! -//! ### Schemes Specifications +//! ### Specifications //! -//! - [VRF Schemes Details](https://github.com/davxy/bandersnatch-vrf-spec) -//! - [Ring VRF ZK Proof](https://github.com/davxy/ring-proof-spec) +//! - [VRF Schemes](https://github.com/davxy/bandersnatch-vrf-spec) +//! - [Ring Proof](https://github.com/davxy/ring-proof-spec) //! -//! ### Built-In suites +//! ## Built-In suites //! //! The library conditionally includes the following pre-configured suites (see features section): //! @@ -29,70 +46,30 @@ //! - **JubJub** (_Edwards curve on BLS12-381_): Supports IETF, Pedersen, and Ring VRF. //! - **Baby-JubJub** (_Edwards curve on BN254_): Supports IETF, Pedersen, and Ring VRF. //! -//! ### Basic Usage +//! ## Basic Usage //! //! ```rust,ignore //! use ark_vrf::suites::bandersnatch::*; -//! let secret = Secret::from_seed(b"example seed"); -//! let public = secret.public(); -//! let input = Input::new(b"example input").unwrap(); -//! let output = secret.output(input); -//! let aux_data = b"optional aux data"; -//! ``` -//! #### IETF-VRF //! -//! _Prove_ -//! ```rust,ignore -//! use ark_vrf::ietf::Prover; -//! let proof = secret.prove(input, output, aux_data); -//! ``` -//! -//! _Verify_ -//! ```rust,ignore -//! use ark_vrf::ietf::Verifier; -//! let result = public.verify(input, output, aux_data, &proof); -//! ``` -//! -//! #### Ring-VRF +//! // Create a secret key from a seed +//! let secret = Secret::from_seed(b"example seed"); //! -//! _Ring construction_ -//! ```rust,ignore -//! const RING_SIZE: usize = 100; -//! let prover_key_index = 3; -//! // Construct an example ring with dummy keys -//! let mut ring = (0..RING_SIZE).map(|i| Secret::from_seed(&i.to_le_bytes()).public().0).collect(); -//! // Patch the ring with the public key of the prover -//! ring[prover_key_index] = public.0; -//! // Any key can be replaced with the padding point -//! ring[0] = RingProofParams::padding_point(); -//! ``` +//! // Derive the corresponding public key +//! let public = secret.public(); //! -//! _Ring parameters construction_ -//! ```rust,ignore -//! let params = RingProofParams::from_seed(RING_SIZE, b"example seed"); -//! ``` +//! // Create an input by hashing data to a curve point +//! let input = Input::new(b"example input").unwrap(); //! -//! _Prove_ -//! ```rust,ignore -//! use ark_vrf::ring::Prover; -//! let prover_key = params.prover_key(&ring); -//! let prover = params.prover(prover_key, prover_key_index); -//! let proof = secret.prove(input, output, aux_data, &prover); -//! ``` +//! // Compute the VRF output (gamma point) +//! let output = secret.output(input); //! -//! _Verify_ -//! ```rust,ignore -//! use ark_vrf::ring::Verifier; -//! let verifier_key = params.verifier_key(&ring); -//! let verifier = params.verifier(verifier_key); -//! let result = Public::verify(input, output, aux_data, &proof, &verifier); +//! // The VRF output can be hashed to obtain a pseudorandom byte string: +//! let hash_bytes = output.hash(); //! ``` //! -//! _Verifier key from commitment_ -//! ```rust,ignore -//! let ring_commitment = params.verifier_key().commitment(); -//! let verifier_key = params.verifier_key_from_commitment(ring_commitment); -//! ``` +//! - [ietf] vrf proof +//! - [pedersen] vrf proof +//! - [ring] vrf proof //! //! ## Features //! @@ -268,7 +245,10 @@ pub trait Suite: Copy { } } -/// Secret key. +/// Secret key for VRF operations. +/// +/// This structure contains the private scalar and caches the corresponding +/// public key. The scalar is automatically zeroized when the struct is dropped. #[derive(Debug, Clone, PartialEq)] pub struct Secret { // Secret scalar. @@ -354,43 +334,66 @@ impl Secret { } /// Public key generic over the cipher suite. +/// +/// This is the public component of a VRF key pair, represented as a point on an elliptic curve. +/// It's used for verifying VRF proofs and can be safely shared publicly. #[derive(Debug, Copy, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct Public(pub AffinePoint); impl Public { /// Construct from inner affine point. + /// + /// This allows creating a public key from an existing curve point. pub fn from(value: AffinePoint) -> Self { Self(value) } } /// VRF input point generic over the cipher suite. +/// +/// This represents an input to the VRF, which is a point on the elliptic curve. +/// Typically created by hashing arbitrary data to a curve point. #[derive(Debug, Clone, Copy, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)] pub struct Input(pub AffinePoint); impl Input { /// Construct from [`Suite::data_to_point`]. + /// + /// This maps arbitrary input data to a curve point using the suite's hash-to-curve function. + /// Returns `None` if the data cannot be mapped to a valid curve point. pub fn new(data: &[u8]) -> Option { S::data_to_point(data).map(Input) } /// Construct from inner affine point. + /// + /// This allows creating an input from an existing curve point. pub fn from(value: AffinePoint) -> Self { Self(value) } } /// VRF output point generic over the cipher suite. +/// +/// This represents the output of the VRF evaluation, which is a point on the elliptic curve. +/// The output can be hashed to produce a deterministic byte string for applications +/// requiring uniform randomness. #[derive(Debug, Clone, Copy, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)] pub struct Output(pub AffinePoint); impl Output { /// Construct from inner affine point. + /// + /// This allows creating an output from an existing curve point. pub fn from(value: AffinePoint) -> Self { Self(value) } - /// Hash using `[Suite::point_to_hash]`. + /// Hash the output point to produce a deterministic byte string. + /// + /// This converts the elliptic curve point to a uniform byte string using + /// the suite's point-to-hash function. The resulting bytes can be used + /// as pseudorandom values for applications. pub fn hash(&self) -> HashOutput { S::point_to_hash(&self.0) } diff --git a/src/pedersen.rs b/src/pedersen.rs index 575291c..22eccf6 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -1,4 +1,38 @@ -//! Pedersen VRF +//! # Pedersen-VRF +//! +//! The Pedersen VRF extends the IETF scheme with key-hiding properties +//! using Pedersen commitments. +//! +//! ## Usage +//! +//! ### Prove +//! +//! ```rust,ignore +//! use ark_vrf::pedersen::Prover; +//! +//! // Generate a proof with a blinding factor +//! let (proof, blinding_factor) = secret.prove(input, output, aux_data); +//! +//! // The proof includes a commitment to the public key +//! let key_commitment = proof.key_commitment(); +//! ``` +//! +//! ### Verify +//! +//! ```rust,ignore +//! use ark_vrf::pedersen::Verifier; +//! +//! // Verify without knowing which specific public key was used. +//! // Verifiers that the secret key used to generate `output` is the same as +//! // the secret key used to generate `proof.key_commitment()`. +//! let result = Public::verify(input, output, aux_data, &proof); +//! assert!(result.is_ok()); +//! +//! assert_eq!( +//! proof.key_commitment(), +//! (public.0 + S::BLINDING_BASE * blinding_factor).into() +//! ); +//! ``` use crate::ietf::IetfSuite; use crate::*; diff --git a/src/ring.rs b/src/ring.rs index 0bbc633..2dba743 100644 --- a/src/ring.rs +++ b/src/ring.rs @@ -1,6 +1,80 @@ -//! Ring VRF. +//! # Ring VRF. +//! +//! The Ring VRF provides anonymity within a set of public keys using +//! zero-knowledge proofs. //! //! This module is gated by the `ring` feature. +//! +//! ## Usage +//! +//! ### Ring Parameters +//! +//! ```rust,ignore +//! const RING_SIZE: usize = 100; +//! let prover_key_index = 3; +//! +//! // Construct an example ring with dummy keys +//! let mut ring = (0..RING_SIZE) +//! .map(|i| Secret::from_seed(&i.to_le_bytes()).public().0) +//! .collect::>(); +//! +//! // Patch the ring with the public key of the prover +//! ring[prover_key_index] = public.0; +//! +//! // Any key can be replaced with the padding point +//! ring[0] = RingProofParams::padding_point(); +//! +//! // Create parameters for the ring proof system +//! // These parameters are reusable across multiple proofs +//! let params = RingProofParams::from_seed(RING_SIZE, b"example seed"); +//! ``` +//! +//! ### Prove +//! +//! ```rust,ignore +//! use ark_vrf::ring::Prover; +//! +//! // Create a prover key specific to this ring +//! let prover_key = params.prover_key(&ring); +//! +//! // Create a prover instance for the specific position in the ring +//! let prover = params.prover(prover_key, prover_key_index); +//! +//! // Generate a zero-knowledge proof that: +//! // 1. The prover knows a secret key for one of the public keys in the ring +//! // 2. That secret key was used to generate the VRF output +//! let proof = secret.prove(input, output, aux_data, &prover); +//! ``` +//! +//! ### Verify +//! +//! ```rust,ignore +//! use ark_vrf::ring::Verifier; +//! +//! // Create a verifier key for this ring +//! let verifier_key = params.verifier_key(&ring); +//! +//! // Create a verifier instance +//! let verifier = params.verifier(verifier_key); +//! +//! // Verify the proof - this confirms that: +//! // 1. The proof was created by someone who knows a secret key in the ring +//! // 2. The VRF output is correct for the given input +//! // But it does NOT reveal which ring member created the proof +//! let result = Public::verify(input, output, aux_data, &proof, &verifier); +//! assert!(result.is_ok()); +//! ``` +//! +//! #### Verifier key from commitment +//! +//! ```rust,ignore +//! // For efficiency, a commitment to the ring can be shared +//! let ring_commitment = params.verifier_key().commitment(); +//! +//! // A verifier can reconstruct the verifier key from just the commitment +//! // without needing the full ring of public keys +//! let verifier_key = params.verifier_key_from_commitment(ring_commitment); +//! ``` use crate::*; use ark_ec::{ @@ -254,7 +328,7 @@ where /// Construct a new random ring context suitable for the given ring size. /// - /// Calls into [`RingProofParams::from_srs`] with randomly generated [`PcsParams`] + /// Calls into [`RingProofParams::from_pcs_params`] with randomly generated [`PcsParams`] /// large enough to be used for the given `ring_size`. pub fn from_rand(ring_size: usize, rng: &mut impl ark_std::rand::RngCore) -> Self { use ring_proof::pcs::PCS; From f809c23a02080f9e1a46efd7aeb89363c3342960 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 11:59:23 +0200 Subject: [PATCH 02/10] IETF docs --- src/ietf.rs | 92 +++++++++++++++++++++++++++++++++++++---------------- src/lib.rs | 76 +++++++++++++------------------------------ 2 files changed, 86 insertions(+), 82 deletions(-) diff --git a/src/ietf.rs b/src/ietf.rs index 3ca1307..fdd360a 100644 --- a/src/ietf.rs +++ b/src/ietf.rs @@ -1,38 +1,25 @@ -//! ### IETF-VRF +//! # IETF-VRF //! -//! The IETF VRF scheme follows [RFC-9381](https://datatracker.ietf.org/doc/rfc9381) -//! and provides a standardized approach to verifiable random functions. +//! Implementation of the ECVRF scheme defined in [RFC-9381](https://datatracker.ietf.org/doc/rfc9381), +//! extended to support binding additional data to the proof. //! -//! The implementation extends RFC-9381 to allow to sign additional user data together -//! with the VRF input. Refer to for -//! specification extension details. -//! -//! ## Usage -//! -//! ### Prove +//! The extension specification is available at: +//! //! //! ```rust,ignore -//! use ark_vrf::ietf::Prover; +//! // Key generation +//! let secret = Secret::::from_seed(b"seed"); +//! let public = secret.public(); //! -//! // Generate a proof that binds the input, output, and auxiliary data +//! // Proving +//! use ark_vrf::ietf::Prover; +//! let input = Input::from(my_data); +//! let output = secret.output(input); //! let proof = secret.prove(input, output, aux_data); //! -//! // The proof can be serialized for transmission -//! let serialized_proof = proof.serialize_compressed(); -//! ``` -//! -//! ### Verify -//! -//! ```rust,ignore +//! // Verification //! use ark_vrf::ietf::Verifier; -//! -//! // Verify the proof against the public key //! let result = public.verify(input, output, aux_data, &proof); -//! assert!(result.is_ok()); -//! -//! // Verification will fail if any parameter is modified -//! let tampered_output = secret.output(Input::new(b"different input").unwrap()); -//! assert!(public.verify(input, tampered_output, aux_data, &proof).is_err()); //! ``` use super::*; @@ -42,6 +29,10 @@ pub trait IetfSuite: Suite {} impl IetfSuite for T where T: Suite {} /// IETF VRF proof. +/// +/// Schnorr-based proof of correctness for a VRF evaluation: +/// - `c`: Challenge scalar derived from public parameters +/// - `s`: Response scalar satisfying the verification equation #[derive(Debug, Clone)] pub struct Proof { pub c: ScalarField, @@ -102,13 +93,38 @@ impl ark_serialize::Valid for Proof { } } +/// Trait for types that can generate VRF proofs. +/// +/// Implementors can create cryptographic proofs that a VRF output +/// is correctly derived from an input using their secret key. pub trait Prover { - /// Generate a proof for the given input/output and user additional data. + /// Generate a proof for the given input/output and additional data. + /// + /// Creates a non-interactive zero-knowledge proof binding the input, output, + /// and additional data to the prover's public key. + /// + /// * `input` - VRF input point + /// * `output` - VRF output point (γ = x·H) + /// * `ad` - Additional data to bind to the proof fn prove(&self, input: Input, output: Output, ad: impl AsRef<[u8]>) -> Proof; } +/// Trait for entities that can verify VRF proofs. +/// +/// Implementors can verify that a VRF output is correctly derived +/// from an input using a specific public key. pub trait Verifier { - /// Verify a proof for the given input/output and user additional data. + /// Verify a proof for the given input/output and additional data. + /// + /// Verifies the cryptographic relationship between input, output, and proof + /// under the verifier's public key. + /// + /// * `input` - VRF input point + /// * `output` - Claimed VRF output point + /// * `aux` - Additional data bound to the proof + /// * `proof` - The proof to verify + /// + /// Returns `Ok(())` if verification succeeds, `Err(Error::VerificationFailure)` otherwise. fn verify( &self, input: Input, @@ -119,6 +135,16 @@ pub trait Verifier { } impl Prover for Secret { + /// Implements the IETF VRF proving algorithm. + /// + /// This follows the procedure specified in RFC-9381 section 5.1, with extensions + /// to support binding additional data to the proof: + /// + /// 1. Generate a deterministic nonce `k` based on the secret key and input + /// 2. Compute nonce commitments `k_b` and `k_h` + /// 3. Compute the challenge `c` using all public values, nonce commitments and the + /// additional data + /// 4. Compute the response `s = k + c * secret` fn prove(&self, input: Input, output: Output, ad: impl AsRef<[u8]>) -> Proof { let k = S::nonce(&self.scalar, input); @@ -135,6 +161,16 @@ impl Prover for Secret { } impl Verifier for Public { + /// Implements the IETF VRF verification algorithm. + /// + /// This follows the procedure specified in RFC-9381 section 5.3, with extensions + /// to support verifying additional data bound to the proof: + /// + /// 1. Compute `u = s*G - c*Y` where G is the generator and Y is the public key + /// 2. Compute `v = s*H - c*O` where H is the input point and O is the output point + /// 3. Recompute the expected challenge `c_exp` using all public values, `u`, `v` and + /// the additional data + /// 4. Verify that `c_exp == c` from the proof fn verify( &self, input: Input, diff --git a/src/lib.rs b/src/lib.rs index a4fc0cb..b54bfa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,35 +1,21 @@ //! # Elliptic Curve VRF-AD //! -//! This library provides flexible and efficient implementations of Verifiable -//! Random Functions with Additional Data (VRF-AD), a cryptographic construct -//! that augments a standard VRF scheme by incorporating auxiliary information -//! into its signature. +//! Implementations of Verifiable Random Functions with Additional Data (VRF-AD) +//! based on elliptic curve cryptography. Built on the [Arkworks](https://github.com/arkworks-rs) +//! framework with configurable cryptographic parameters. //! -//! It leverages the [Arkworks](https://github.com/arkworks-rs) framework and -//! supports customization of scheme parameters. +//! VRF-AD extends standard VRF constructions by binding auxiliary data to the proof, +//! providing stronger contextual security guarantees. //! -//! ## What is a VRF? +//! ## Schemes //! -//! A Verifiable Random Function (VRF) is a cryptographic primitive that maps inputs -//! to verifiable pseudorandom outputs. Key properties include: +//! - **IETF VRF**: ECVRF implementation compliant with [RFC9381](https://datatracker.ietf.org/doc/rfc9381) //! -//! - **Uniqueness**: For a given input and private key, there is exactly one valid output -//! - **Verifiability**: Anyone with the public key can verify that an output is correct -//! - **Pseudorandomness**: Without the private key, outputs appear random and unpredictable -//! - **Collision resistance**: Finding inputs that map to the same output is computationally infeasible +//! - **Pedersen VRF**: Key-hiding VRF using Pedersen commitments as described in +//! [BCHSV23](https://eprint.iacr.org/2023/002) //! -//! ## Supported Schemes -//! -//! - **IETF VRF**: Complies with ECVRF described in [RFC9381](https://datatracker.ietf.org/doc/rfc9381). -//! This is a standardized VRF implementation suitable for most applications requiring -//! verifiable randomness. -//! -//! - **Pedersen VRF**: Described in [BCHSV23](https://eprint.iacr.org/2023/002). -//! Extends the basic VRF with key-hiding properties using Pedersen commitments, -//! -//! - **Ring VRF**: A zero-knowledge-based scheme inspired by [BCHSV23](https://eprint.iacr.org/2023/002). -//! Provides signer anonymity within a set of public keys (a "ring"), allowing -//! verification that a ring member created the proof without revealing which specific member. +//! - **Ring VRF**: Zero-knowledge VRF with signer anonymity within a key set, based on +//! [BCHSV23](https://eprint.iacr.org/2023/002) //! //! ### Specifications //! @@ -46,27 +32,20 @@ //! - **JubJub** (_Edwards curve on BLS12-381_): Supports IETF, Pedersen, and Ring VRF. //! - **Baby-JubJub** (_Edwards curve on BN254_): Supports IETF, Pedersen, and Ring VRF. //! -//! ## Basic Usage +//! ## Usage //! //! ```rust,ignore //! use ark_vrf::suites::bandersnatch::*; //! -//! // Create a secret key from a seed //! let secret = Secret::from_seed(b"example seed"); -//! -//! // Derive the corresponding public key //! let public = secret.public(); -//! -//! // Create an input by hashing data to a curve point //! let input = Input::new(b"example input").unwrap(); -//! -//! // Compute the VRF output (gamma point) //! let output = secret.output(input); -//! -//! // The VRF output can be hashed to obtain a pseudorandom byte string: //! let hash_bytes = output.hash(); //! ``` //! +//! ### Proof Generation Schemes +//! //! - [ietf] vrf proof //! - [pedersen] vrf proof //! - [ring] vrf proof @@ -247,8 +226,8 @@ pub trait Suite: Copy { /// Secret key for VRF operations. /// -/// This structure contains the private scalar and caches the corresponding -/// public key. The scalar is automatically zeroized when the struct is dropped. +/// Contains the private scalar and cached public key. +/// Implements automatic zeroization on drop. #[derive(Debug, Clone, PartialEq)] pub struct Secret { // Secret scalar. @@ -335,8 +314,7 @@ impl Secret { /// Public key generic over the cipher suite. /// -/// This is the public component of a VRF key pair, represented as a point on an elliptic curve. -/// It's used for verifying VRF proofs and can be safely shared publicly. +/// Elliptic curve point representing the public component of a VRF key pair. #[derive(Debug, Copy, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct Public(pub AffinePoint); @@ -351,23 +329,19 @@ impl Public { /// VRF input point generic over the cipher suite. /// -/// This represents an input to the VRF, which is a point on the elliptic curve. -/// Typically created by hashing arbitrary data to a curve point. +/// Elliptic curve point representing the VRF input. #[derive(Debug, Clone, Copy, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)] pub struct Input(pub AffinePoint); impl Input { /// Construct from [`Suite::data_to_point`]. /// - /// This maps arbitrary input data to a curve point using the suite's hash-to-curve function. - /// Returns `None` if the data cannot be mapped to a valid curve point. + /// Maps arbitrary data to a curve point via hash-to-curve. pub fn new(data: &[u8]) -> Option { S::data_to_point(data).map(Input) } /// Construct from inner affine point. - /// - /// This allows creating an input from an existing curve point. pub fn from(value: AffinePoint) -> Self { Self(value) } @@ -375,9 +349,7 @@ impl Input { /// VRF output point generic over the cipher suite. /// -/// This represents the output of the VRF evaluation, which is a point on the elliptic curve. -/// The output can be hashed to produce a deterministic byte string for applications -/// requiring uniform randomness. +/// Elliptic curve point representing the VRF output. #[derive(Debug, Clone, Copy, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)] pub struct Output(pub AffinePoint); @@ -389,11 +361,7 @@ impl Output { Self(value) } - /// Hash the output point to produce a deterministic byte string. - /// - /// This converts the elliptic curve point to a uniform byte string using - /// the suite's point-to-hash function. The resulting bytes can be used - /// as pseudorandom values for applications. + /// Hash the output point to a deterministic byte string. pub fn hash(&self) -> HashOutput { S::point_to_hash(&self.0) } @@ -428,7 +396,7 @@ macro_rules! suite_types { mod tests { use super::*; use suites::testing::{Input, Secret}; - use testing::{TEST_SEED, random_val}; + use testing::{random_val, TEST_SEED}; #[test] fn vrf_output_check() { From 779684a16b261ab3d48bc40f9bbdc179b2d26e3b Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 12:06:47 +0200 Subject: [PATCH 03/10] Pedersen docs --- README.md | 10 +++--- src/pedersen.rs | 85 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 60 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 58f9416..8d741b6 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ _Prove_ use ark_vrf::pedersen::Prover; // Generate a proof with a blinding factor -let (proof, blinding_factor) = secret.prove(input, output, aux_data); +let (proof, blinding) = secret.prove(input, output, aux_data); // The proof includes a commitment to the public key let key_commitment = proof.key_commitment(); @@ -128,10 +128,10 @@ use ark_vrf::pedersen::Verifier; let result = Public::verify(input, output, aux_data, &proof); assert!(result.is_ok()); -assert_eq!( - proof.key_commitment(), - (public.0 + S::BLINDING_BASE * blinding_factor).into() -); +// Verify the proof was created using a specific public key +// This requires knowledge of the blinding factor +let expected_commitment = (public.0 + MySuite::BLINDING_BASE * blinding).into_affine(); +assert_eq!(proof.key_commitment(), expected_commitment); ``` ### Ring-VRF diff --git a/src/pedersen.rs b/src/pedersen.rs index 22eccf6..fb0a836 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -1,37 +1,30 @@ //! # Pedersen-VRF //! -//! The Pedersen VRF extends the IETF scheme with key-hiding properties -//! using Pedersen commitments. +//! Implementation of a key-hiding VRF scheme using Pedersen commitments as described in +//! [BCHSV23](https://eprint.iacr.org/2023/002). //! -//! ## Usage -//! -//! ### Prove +//! This scheme extends the IETF VRF by adding key privacy through blinding factors, +//! allowing verification without revealing which specific public key was used. //! //! ```rust,ignore -//! use ark_vrf::pedersen::Prover; -//! -//! // Generate a proof with a blinding factor -//! let (proof, blinding_factor) = secret.prove(input, output, aux_data); -//! -//! // The proof includes a commitment to the public key -//! let key_commitment = proof.key_commitment(); -//! ``` +//! // Key generation +//! let secret = Secret::::from_seed(b"seed"); +//! let public = secret.public(); //! -//! ### Verify +//! // Proving +//! use ark_vrf::pedersen::Prover; +//! let input = Input::from(my_data); +//! let output = secret.output(input); +//! let (proof, blinding) = secret.prove(input, output, aux_data); //! -//! ```rust,ignore +//! // Verification //! use ark_vrf::pedersen::Verifier; -//! -//! // Verify without knowing which specific public key was used. -//! // Verifiers that the secret key used to generate `output` is the same as -//! // the secret key used to generate `proof.key_commitment()`. //! let result = Public::verify(input, output, aux_data, &proof); -//! assert!(result.is_ok()); //! -//! assert_eq!( -//! proof.key_commitment(), -//! (public.0 + S::BLINDING_BASE * blinding_factor).into() -//! ); +//! // Verify the proof was created using a specific public key +//! // This requires knowledge of the blinding factor +//! let expected_commitment = (public.0 + MySuite::BLINDING_BASE * blinding).into_affine(); +//! assert_eq!(proof.key_commitment(), expected_commitment); //! ``` use crate::ietf::IetfSuite; @@ -68,7 +61,14 @@ pub trait PedersenSuite: IetfSuite { } } -/// Pedersen proof. +/// Pedersen VRF proof. +/// +/// Zero-knowledge proof with key-hiding properties: +/// - `pk_com`: Commitment to the public key (Y_b = x·G + b·B) +/// - `r`: Nonce commitment for the generator (R = k·G + k_b·B) +/// - `ok`: Nonce commitment for the input point (O_k = k·I) +/// - `s`: Response scalar for the secret key +/// - `sb`: Response scalar for the blinding factor #[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)] pub struct Proof { pk_com: AffinePoint, @@ -85,8 +85,20 @@ impl Proof { } } +/// Trait for types that can generate Pedersen VRF proofs. +/// +/// Implementors can create zero-knowledge proofs that a VRF output +/// is correctly derived from an input using their secret key, +/// while hiding the specific public key used. pub trait Prover { - /// Generate a proof for the given input/output and user additional data. + /// Generate a proof for the given input/output and additional data. + /// + /// Creates a zero-knowledge proof binding the input, output, and additional data + /// to a commitment of the prover's public key rather than the key itself. + /// + /// * `input` - VRF input point + /// * `output` - VRF output point (γ = x·H) + /// * `ad` - Additional data to bind to the proof /// /// Returns the proof together with the associated blinding factor. fn prove( @@ -97,11 +109,24 @@ pub trait Prover { ) -> (Proof, ScalarField); } +/// Trait for entities that can verify Pedersen VRF proofs. +/// +/// Implementors can verify that a VRF output is correctly derived +/// from an input using a committed public key. pub trait Verifier { - /// Verify a proof for the given input/output and user additional data. + /// Verify a proof for the given input/output and additional data. + /// + /// Verifies the cryptographic relationship between input, output, and proof + /// without requiring knowledge of which specific public key was used. + /// Confirms that the secret key used to generate the output is the same as + /// the one committed to in the proof. + /// + /// * `input` - VRF input point + /// * `output` - Claimed VRF output point + /// * `ad` - Additional data bound to the proof + /// * `proof` - The proof to verify /// - /// Verifiers that the secret key used to generate `output` is the same as - /// the secret key used to generate `proof.key_commitment()`. + /// Returns `Ok(())` if verification succeeds, `Err(Error::VerificationFailure)` otherwise. fn verify( input: Input, output: Output, @@ -191,7 +216,7 @@ impl Verifier for Public { #[cfg(test)] pub(crate) mod testing { use super::*; - use crate::testing::{self as common, CheckPoint, SuiteExt, TEST_SEED, random_val}; + use crate::testing::{self as common, random_val, CheckPoint, SuiteExt, TEST_SEED}; pub fn prove_verify() { use pedersen::{Prover, Verifier}; From 52bfb904c52a8ac478375f2d5541a376db88d40d Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 12:24:53 +0200 Subject: [PATCH 04/10] Ring vrf docs --- src/ietf.rs | 2 + src/pedersen.rs | 2 + src/ring.rs | 207 +++++++++++++++++++++++++----------------------- 3 files changed, 113 insertions(+), 98 deletions(-) diff --git a/src/ietf.rs b/src/ietf.rs index fdd360a..3a2435d 100644 --- a/src/ietf.rs +++ b/src/ietf.rs @@ -6,6 +6,8 @@ //! The extension specification is available at: //! //! +//! ## Usage Example +//! //! ```rust,ignore //! // Key generation //! let secret = Secret::::from_seed(b"seed"); diff --git a/src/pedersen.rs b/src/pedersen.rs index fb0a836..6b8bd36 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -6,6 +6,8 @@ //! This scheme extends the IETF VRF by adding key privacy through blinding factors, //! allowing verification without revealing which specific public key was used. //! +//! ## Usage Example +//! //! ```rust,ignore //! // Key generation //! let secret = Secret::::from_seed(b"seed"); diff --git a/src/ring.rs b/src/ring.rs index 2dba743..d523181 100644 --- a/src/ring.rs +++ b/src/ring.rs @@ -1,79 +1,41 @@ -//! # Ring VRF. +//! # Ring VRF //! -//! The Ring VRF provides anonymity within a set of public keys using -//! zero-knowledge proofs. +//! Implementation of a zero-knowledge VRF scheme providing signer anonymity within a set of +//! public keys, based on [BCHSV23](https://eprint.iacr.org/2023/002). //! //! This module is gated by the `ring` feature. //! -//! ## Usage -//! -//! ### Ring Parameters +//! ## Usage Example //! //! ```rust,ignore +//! // Ring setup //! const RING_SIZE: usize = 100; //! let prover_key_index = 3; //! -//! // Construct an example ring with dummy keys +//! // Create a ring of public keys //! let mut ring = (0..RING_SIZE) //! .map(|i| Secret::from_seed(&i.to_le_bytes()).public().0) //! .collect::>(); -//! -//! // Patch the ring with the public key of the prover //! ring[prover_key_index] = public.0; //! -//! // Any key can be replaced with the padding point -//! ring[0] = RingProofParams::padding_point(); -//! -//! // Create parameters for the ring proof system -//! // These parameters are reusable across multiple proofs +//! // Initialize ring parameters //! let params = RingProofParams::from_seed(RING_SIZE, b"example seed"); -//! ``` //! -//! ### Prove -//! -//! ```rust,ignore +//! // Proving //! use ark_vrf::ring::Prover; -//! -//! // Create a prover key specific to this ring //! let prover_key = params.prover_key(&ring); -//! -//! // Create a prover instance for the specific position in the ring //! let prover = params.prover(prover_key, prover_key_index); -//! -//! // Generate a zero-knowledge proof that: -//! // 1. The prover knows a secret key for one of the public keys in the ring -//! // 2. That secret key was used to generate the VRF output //! let proof = secret.prove(input, output, aux_data, &prover); -//! ``` //! -//! ### Verify -//! -//! ```rust,ignore +//! // Verification //! use ark_vrf::ring::Verifier; -//! -//! // Create a verifier key for this ring //! let verifier_key = params.verifier_key(&ring); -//! -//! // Create a verifier instance //! let verifier = params.verifier(verifier_key); -//! -//! // Verify the proof - this confirms that: -//! // 1. The proof was created by someone who knows a secret key in the ring -//! // 2. The VRF output is correct for the given input -//! // But it does NOT reveal which ring member created the proof //! let result = Public::verify(input, output, aux_data, &proof, &verifier); -//! assert!(result.is_ok()); -//! ``` //! -//! #### Verifier key from commitment -//! -//! ```rust,ignore -//! // For efficiency, a commitment to the ring can be shared -//! let ring_commitment = params.verifier_key().commitment(); -//! -//! // A verifier can reconstruct the verifier key from just the commitment -//! // without needing the full ring of public keys -//! let verifier_key = params.verifier_key_from_commitment(ring_commitment); +//! // Efficient verification with commitment +//! let ring_commitment = verifier_key.commitment(); +//! let reconstructed_key = params.verifier_key_from_commitment(ring_commitment); //! ``` use crate::*; @@ -189,6 +151,10 @@ pub type RingVerifier = pub type RingBareProof = ring_proof::RingProof, Pcs>; /// Ring VRF proof. +/// +/// Two-part zero-knowledge proof with signer anonymity: +/// - `pedersen_proof`: Key commitment and VRF correctness proof +/// - `ring_proof`: Membership proof binding the commitment to the ring #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] pub struct Proof where @@ -200,7 +166,10 @@ where pub ring_proof: RingBareProof, } -/// Ring VRF prover. +/// Trait for types that can generate Ring VRF proofs. +/// +/// Implementors can create anonymous proofs that a VRF output +/// is correctly derived using a secret key from a ring of public keys. pub trait Prover where BaseField: ark_ff::PrimeField, @@ -208,6 +177,15 @@ where AffinePoint: TEMapping>, { /// Generate a proof for the given input/output and additional data. + /// + /// Creates a zero-knowledge proof that: + /// 1. The prover knows a secret key for one of the ring's public keys + /// 2. That secret key was used to compute the VRF output + /// + /// * `input` - VRF input point + /// * `output` - VRF output point + /// * `ad` - Additional data to bind to the proof + /// * `prover` - Ring prover instance for the specific ring position fn prove( &self, input: Input, @@ -217,14 +195,30 @@ where ) -> Proof; } -/// Ring VRF verifier. +/// Trait for entities that can verify Ring VRF proofs. +/// +/// Implementors can verify anonymous proofs that a VRF output +/// was derived using a secret key from a ring of public keys. pub trait Verifier where BaseField: ark_ff::PrimeField, CurveConfig: TECurveConfig, AffinePoint: TEMapping>, { - /// Verify a proof for the given input/output and user additional data. + /// Verify a proof for the given input/output and additional data. + /// + /// Verifies that: + /// 1. The proof was created by a member of the ring + /// 2. The VRF output is correct for the given input + /// 3. The additional data matches what was used during proving + /// + /// * `input` - VRF input point + /// * `output` - Claimed VRF output point + /// * `ad` - Additional data bound to the proof + /// * `sig` - The proof to verify + /// * `verifier` - Ring verifier instance for the specific ring + /// + /// Returns `Ok(())` if verification succeeds, `Err(Error::VerificationFailure)` otherwise. fn verify( input: Input, output: Output, @@ -281,9 +275,11 @@ where } } -/// Ring proof full parameters. +/// Ring proof parameters. /// -/// Wraps [`PcsParams`] and [`PiopParams`]. +/// Contains the cryptographic parameters needed for ring proof generation and verification: +/// - `pcs`: Polynomial Commitment Scheme parameters (KZG setup) +/// - `piop`: Polynomial Interactive Oracle Proof parameters #[derive(Clone)] pub struct RingProofParams where @@ -317,19 +313,18 @@ where CurveConfig: TECurveConfig + Clone, AffinePoint: TEMapping>, { - /// Construct new ring proof params suitable for the given ring size. + /// Construct deterministic ring proof params for the given ring size. /// - /// Calls into [`RingProofParams::from_rand`] with a `ChaCha20Rng` seeded with `seed`. + /// Creates parameters using a deterministic `ChaCha20Rng` seeded with `seed`. pub fn from_seed(ring_size: usize, seed: [u8; 32]) -> Self { use ark_std::rand::SeedableRng; let mut rng = rand_chacha::ChaCha20Rng::from_seed(seed); Self::from_rand(ring_size, &mut rng) } - /// Construct a new random ring context suitable for the given ring size. + /// Construct random ring proof params for the given ring size. /// - /// Calls into [`RingProofParams::from_pcs_params`] with randomly generated [`PcsParams`] - /// large enough to be used for the given `ring_size`. + /// Generates a new KZG setup with sufficient degree to support the specified ring size. pub fn from_rand(ring_size: usize, rng: &mut impl ark_std::rand::RngCore) -> Self { use ring_proof::pcs::PCS; let max_degree = pcs_domain_size::(ring_size) - 1; @@ -337,18 +332,19 @@ where Self::from_pcs_params(ring_size, pcs_params).expect("PCS params is correct") } - /// Construct a new random ring context suitable for the given [`PcsParams`]. + /// Construct ring proof params from existing KZG setup. /// - /// Fails if the domain representable via the supplied `PcsParams` is not sufficiently - /// large for the given `ring_size`. + /// Creates parameters using an existing KZG setup, truncating if larger than needed + /// or returning an error if the setup is insufficient for the specified ring size. /// - /// If the domain size of `PcsParams` exceeds the required limit, the extra items are truncated. + /// * `ring_size` - Maximum number of keys in the ring + /// * `pcs_params` - KZG setup parameters pub fn from_pcs_params(ring_size: usize, mut pcs_params: PcsParams) -> Result { let pcs_domain_size = pcs_domain_size::(ring_size); if pcs_params.powers_in_g1.len() < pcs_domain_size || pcs_params.powers_in_g2.len() < 2 { return Err(Error::InvalidData); } - // Keep only the required powers of tau. + // Keep only the required powers of tau pcs_params.powers_in_g1.truncate(pcs_domain_size); pcs_params.powers_in_g2.truncate(2); let piop_domain_size = piop_domain_size::(ring_size); @@ -364,18 +360,21 @@ where self.piop.keyset_part_size } - /// Construct [`RingProverKey`] for the given ring. + /// Create a prover key for the given ring of public keys. + /// + /// Indexes the ring and prepares the cryptographic material needed for proving. + /// If the ring exceeds the maximum supported size, excess keys are ignored. /// - /// Note: if `pks.len() > self.max_ring_size()` the extra keys in the tail are ignored. + /// * `pks` - Array of public keys forming the ring pub fn prover_key(&self, pks: &[AffinePoint]) -> RingProverKey { let pks = TEMapping::to_te_slice(&pks[..pks.len().min(self.max_ring_size())]); ring_proof::index(&self.pcs, &self.piop, &pks).0 } - /// Construct [`RingProver`] from [`RingProverKey`] for the prover implied by `key_index`. + /// Create a prover instance for a specific position in the ring. /// - /// Key index is the prover index within the `pks` sequence passed to construct the - /// [`RingProverKey`] via the `prover_key` method. + /// * `prover_key` - Ring prover key created with `prover_key()` + /// * `key_index` - Position of the prover's public key in the original ring pub fn prover(&self, prover_key: RingProverKey, key_index: usize) -> RingProver { RingProver::::init( prover_key, @@ -385,20 +384,23 @@ where ) } - /// Construct a `RingVerifierKey` instance for the given ring. + /// Create a verifier key for the given ring of public keys. /// - /// Note: if `pks.len() > self.max_ring_size()` the extra keys in the tail are ignored. + /// Indexes the ring and prepares the cryptographic material needed for verification. + /// If the ring exceeds the maximum supported size, excess keys are ignored. + /// + /// * `pks` - Array of public keys forming the ring pub fn verifier_key(&self, pks: &[AffinePoint]) -> RingVerifierKey { let pks = TEMapping::to_te_slice(&pks[..pks.len().min(self.max_ring_size())]); ring_proof::index(&self.pcs, &self.piop, &pks).1 } - /// Construct `RingVerifierKey` instance for the ring previously committed. + /// Create a verifier key from a precomputed ring commitment. /// - /// The `RingCommitment` instance can be obtained via the `VerifierKey::commitment()` method. + /// Allows efficient reconstruction of a verifier key without needing the full ring. + /// The commitment can be obtained from an existing verifier key via `commitment()`. /// - /// This allows to quickly reconstruct the verifier key without having to recompute the - /// keys commitment. + /// * `commitment` - Precomputed commitment to the ring of public keys pub fn verifier_key_from_commitment( &self, commitment: RingCommitment, @@ -407,10 +409,10 @@ where RingVerifierKey::::from_commitment_and_kzg_vk(commitment, self.pcs.raw_vk()) } - /// Builder for incremental construction of the verifier key. + /// Create a builder for incremental construction of the verifier key. /// - /// This also returns a `RingBuilderPcsParams` which may be used to append new key items - /// to the `RingVerifierKeyBuilder` instance its tne `SrsLookup` implementation. + /// Returns a builder and associated PCS parameters that can be used to + /// construct a verifier key by adding public keys in batches. pub fn verifier_key_builder(&self) -> (RingVerifierKeyBuilder, RingBuilderPcsParams) { type RingBuilderKey = ring_proof::ring::RingBuilderKey, ::Pairing>; @@ -421,7 +423,9 @@ where (builder, builder_pcs_params) } - /// Construct `RingVerifier` from `RingVerifierKey`. + /// Create a verifier instance from a verifier key. + /// + /// * `verifier_key` - Ring verifier key created with `verifier_key()` pub fn verifier(&self, verifier_key: RingVerifierKey) -> RingVerifier { RingVerifier::::init( verifier_key, @@ -430,13 +434,14 @@ where ) } - /// Constructs a `RingVerifier` from `RingVerifierKey` without no `RingProofParams`. + /// Create a verifier instance without requiring the full parameters. /// - /// While this approach is slightly less efficient than using pre-constructed `RingProofParams`, - /// as some parameters need to be computed on-the-fly, it is beneficial in memory or - /// storage constrained environments. This avoids the need to retain the full `RingProofParams` for - /// ring signature verification. Instead, the `VerifierKey` contains only the essential information - /// needed to verify ring proofs. + /// Creates a verifier using only the verifier key and ring size, computing + /// necessary parameters on-the-fly. This is more memory efficient but slightly + /// less computationally efficient than using the full parameters. + /// + /// * `verifier_key` - Ring verifier key + /// * `ring_size` - Size of the ring used to create the verifier key pub fn verifier_no_context( verifier_key: RingVerifierKey, ring_size: usize, @@ -529,7 +534,10 @@ type PartialRingCommitment = type RawVerifierKey = as ring_proof::pcs::PcsParams>::RVK; -/// Ring verifier key builder. +/// Builder for incremental construction of ring verifier keys. +/// +/// Allows constructing a verifier key by adding public keys in batches, +/// which is useful for large rings or memory-constrained environments. #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] pub struct RingVerifierKeyBuilder where @@ -544,7 +552,9 @@ where pub type G1Affine = <::Pairing as Pairing>::G1Affine; pub type G2Affine = <::Pairing as Pairing>::G2Affine; -/// Lagrangian form SRS entries lookup. +/// Trait for accessing Structured Reference String entries in Lagrangian basis. +/// +/// Provides access to precomputed SRS elements needed for efficient ring operations. pub trait SrsLookup where BaseField: ark_ff::PrimeField, @@ -586,7 +596,10 @@ where CurveConfig: TECurveConfig + Clone, AffinePoint: TEMapping>, { - /// Construct an empty ring verifier key builder. + /// Create a new empty ring verifier key builder. + /// + /// * `params` - Ring proof parameters + /// * `lookup` - SRS lookup implementation for accessing precomputed values pub fn new(params: &RingProofParams, lookup: impl SrsLookup) -> Self { use ring_proof::pcs::PcsParams; let lookup = |range: Range| lookup.lookup(range).ok_or(()); @@ -596,21 +609,19 @@ where RingVerifierKeyBuilder { partial, raw_vk } } - /// Free public key slots. + /// Get the number of remaining slots available in the ring. #[inline(always)] pub fn free_slots(&self) -> usize { self.partial.max_keys - self.partial.curr_keys } - /// Append a new member to the ring verifier key. + /// Add public keys to the ring being built. /// - /// If the `pks` length is greater than the number of available slots in the ring - /// then an error is returned with the available slots count. + /// * `pks` - Public keys to add to the ring + /// * `lookup` - SRS lookup implementation for accessing precomputed values /// - /// If the available free slots are not sufficient to append `pks` sequence, the - /// number of available slots are returned in the error variant. - /// If the supplied `lookup` returns `None`, then an error with `usize::MAX` is - /// returned. + /// Returns `Ok(())` if keys were added successfully, or `Err(available_slots)` + /// if there's not enough space. Returns `Err(usize::MAX)` if SRS lookup fails. pub fn append( &mut self, pks: &[AffinePoint], @@ -634,7 +645,7 @@ where Ok(()) } - /// Build verifier key. + /// Complete the building process and create the verifier key. pub fn finalize(self) -> RingVerifierKey { RingVerifierKey::::from_ring_and_kzg_vk(&self.partial, self.raw_vk) } From 75b9b5adfdac8fc907a77abb4bbc032af1a104ed Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 12:41:14 +0200 Subject: [PATCH 05/10] Utils docs --- src/utils/common.rs | 104 ++++++++++++++++++++++++++++++++++++----- src/utils/mod.rs | 25 +++++++--- src/utils/te_sw_map.rs | 46 ++++++++++++++++-- 3 files changed, 152 insertions(+), 23 deletions(-) diff --git a/src/utils/common.rs b/src/utils/common.rs index a4efc5d..595f098 100644 --- a/src/utils/common.rs +++ b/src/utils/common.rs @@ -1,7 +1,13 @@ +//! Common cryptographic utility functions. +//! +//! This module provides implementations of various cryptographic operations +//! used throughout the VRF schemes, including hashing, challenge generation, +//! and hash-to-curve algorithms. + use crate::*; use ark_ec::{ - AffineRepr, hashing::curve_maps::elligator2::{Elligator2Config, Elligator2Map}, + AffineRepr, }; use ark_ff::PrimeField; use digest::{Digest, FixedOutputReset}; @@ -9,12 +15,17 @@ use digest::{Digest, FixedOutputReset}; #[cfg(not(feature = "std"))] use ark_std::vec::Vec; -// Generic hash wrapper. +/// Generic hash wrapper. +/// +/// Computes a hash of the provided data using the specified hash function. pub fn hash(data: &[u8]) -> digest::Output { H::new().chain_update(data).finalize() } /// Generic HMAC wrapper. +/// +/// Computes an HMAC of the provided data using the specified key and hash function. +/// Used for deterministic nonce generation in RFC-6979. #[cfg(feature = "rfc-6979")] fn hmac(sk: &[u8], data: &[u8]) -> Vec { use hmac::{Mac, SimpleHmac}; @@ -29,7 +40,8 @@ fn hmac(sk: &[u8], data: &[u8]) -> /// Try-And-Increment (TAI) method as defined by RFC 9381 section 5.4.1.1. /// /// Implements ECVRF_encode_to_curve in a simple and generic way that works -/// for any elliptic curve. +/// for any elliptic curve. This method iteratively attempts to hash the input +/// with an incrementing counter until a valid curve point is found. /// /// To use this algorithm, hash length MUST be at least equal to the field length. /// @@ -39,6 +51,15 @@ fn hmac(sk: &[u8], data: &[u8]) -> /// /// May systematically fail if `Suite::Hasher` output is not sufficient to /// construct a point according to the `Suite::Codec` in use. +/// +/// # Parameters +/// +/// * `data` - The input data to hash to a curve point +/// +/// # Returns +/// +/// * `Some(AffinePoint)` - A valid curve point in the prime-order subgroup +/// * `None` - If no valid point could be found after 256 attempts pub fn hash_to_curve_tai_rfc_9381(data: &[u8]) -> Option> { use ark_ec::AffineRepr; @@ -64,10 +85,22 @@ pub fn hash_to_curve_tai_rfc_9381(data: &[u8]) -> Option)` - A valid curve point in the prime-order subgroup +/// * `None` - If the hash-to-curve operation fails #[allow(unused)] pub fn hash_to_curve_ell2_rfc_9380( data: &[u8], @@ -80,7 +113,7 @@ where Elligator2Map>: ark_ec::hashing::map_to_curve_hasher::MapToCurve< as AffineRepr>::Group>, { - use ark_ec::hashing::{HashToCurve, map_to_curve_hasher::MapToCurveBasedHasher}; + use ark_ec::hashing::{map_to_curve_hasher::MapToCurveBasedHasher, HashToCurve}; use ark_ff::field_hashers::DefaultFieldHasher; // Domain Separation Tag := "ECVRF_" || h2c_suite_ID_string || suite_string @@ -96,6 +129,24 @@ where } /// Challenge generation according to RFC-9381 section 5.4.3. +/// +/// Generates a challenge scalar by hashing a sequence of curve points and additional data. +/// This is used in the Schnorr-like signature scheme for VRF proofs. +/// +/// The function follows the procedure specified in RFC-9381: +/// 1. Start with a domain separator and suite ID +/// 2. Append the encoded form of each provided point +/// 3. Append the additional data +/// 4. Hash the result and interpret it as a scalar +/// +/// # Parameters +/// +/// * `pts` - Array of curve points to include in the challenge +/// * `ad` - Additional data to bind to the challenge +/// +/// # Returns +/// +/// A scalar field element derived from the hash of the inputs pub fn challenge_rfc_9381(pts: &[&AffinePoint], ad: &[u8]) -> ScalarField { const DOM_SEP_START: u8 = 0x02; const DOM_SEP_END: u8 = 0x00; @@ -111,6 +162,9 @@ pub fn challenge_rfc_9381(pts: &[&AffinePoint], ad: &[u8]) -> Scala /// Point to a hash according to RFC-9381 section 5.2. /// +/// Converts an elliptic curve point to a hash value, following the procedure in RFC-9381. +/// This is used to derive the final VRF output bytes from the VRF output point. +/// /// According to the RFC, the input point `pt` should be multiplied by the cofactor /// before being hashed. However, in typical usage, the hashed point is the result /// of a scalar multiplication on a point produced by the `Suite::data_to_point` @@ -123,9 +177,14 @@ pub fn challenge_rfc_9381(pts: &[&AffinePoint], ad: &[u8]) -> Scala /// purpose of multiplying by the cofactor is as a safeguard against potential issues /// with an incorrect implementation of `data_to_point`. /// -/// Since multiplying by the cofactor changes the point being hashed, this step is -/// made optional to accommodate scenarios where strict compliance with the RFC's -/// prescribed procedure is not required. +/// # Parameters +/// +/// * `pt` - The elliptic curve point to hash +/// * `mul_by_cofactor` - Whether to multiply the point by the cofactor before hashing +/// +/// # Returns +/// +/// A hash value derived from the encoded point pub fn point_to_hash_rfc_9381( pt: &AffinePoint, mul_by_cofactor: bool, @@ -146,9 +205,20 @@ pub fn point_to_hash_rfc_9381( /// Nonce generation according to RFC-9381 section 5.4.2.2. /// /// This procedure is based on section 5.1.6 of RFC 8032: "Edwards-Curve Digital -/// Signature Algorithm (EdDSA)". +/// Signature Algorithm (EdDSA)". It generates a deterministic nonce by hashing +/// the secret key and input point together. +/// +/// The deterministic generation ensures that the same nonce is never used twice +/// with the same secret key for different inputs, which is critical for security. /// -/// The algorithm generate the nonce value in a deterministic pseudorandom fashion. +/// # Parameters +/// +/// * `sk` - The secret scalar key +/// * `input` - The input point +/// +/// # Returns +/// +/// A scalar field element to be used as a nonce /// /// # Panics /// @@ -175,7 +245,17 @@ pub fn nonce_rfc_8032(sk: &ScalarField, input: &AffinePoint) -> /// the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature /// Algorithm (ECDSA)". /// -/// The algorithm generate the nonce value in a deterministic pseudorandom fashion. +/// It generates a deterministic nonce using HMAC-based extraction, which provides +/// strong security guarantees against nonce reuse or biased nonce generation. +/// +/// # Parameters +/// +/// * `sk` - The secret scalar key +/// * `input` - The input point +/// +/// # Returns +/// +/// A scalar field element to be used as a nonce #[cfg(feature = "rfc-6979")] pub fn nonce_rfc_6979(sk: &ScalarField, input: &AffinePoint) -> ScalarField where diff --git a/src/utils/mod.rs b/src/utils/mod.rs index cbd8bc7..29a639e 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,20 +1,31 @@ -//! Common utilities +//! # Common utilities +//! +//! This module provides cryptographic utility functions and curve mappings used +//! throughout the VRF implementations. pub mod common; pub mod te_sw_map; -/// Standard procedures. +/// Standard cryptographic procedures. +/// +/// Includes hash functions, challenge generation, and point-to-hash conversions +/// following RFC-9381 and other standards. pub use common::*; -/// Twisted Edwards to Short Weierstrass mapping. + +/// Twisted Edwards to Short Weierstrass curve mapping. +/// +/// Provides bidirectional mappings between different curve representations, +/// allowing operations to be performed in the most convenient form. pub use te_sw_map::*; /// Point scalar multiplication with optional secret splitting. /// -/// Secret scalar split into the sum of two scalars, which randomly mutate but -/// retain the same sum. Incurs 2x penalty in scalar multiplications, but provides -/// side channel defenses. +/// When the `secret-split` feature is enabled, this macro splits the secret scalar +/// into the sum of two randomly generated scalars that retain the same sum. This +/// technique provides side-channel resistance at the cost of doubling the number +/// of scalar multiplications. /// -/// Note: actual secret splitting is enabled via the `secret-split` feature. +/// Without the feature enabled, it performs a standard scalar multiplication. mod secret_split { #[cfg(feature = "secret-split")] #[doc(hidden)] diff --git a/src/utils/te_sw_map.rs b/src/utils/te_sw_map.rs index 81c7946..b90c21e 100644 --- a/src/utils/te_sw_map.rs +++ b/src/utils/te_sw_map.rs @@ -1,18 +1,33 @@ +//! # Twisted Edwards to Short Weierstrass curve mapping utilities. +//! +//! This module provides bidirectional mappings between different curve representations, +//! allowing operations to be performed in the most convenient form for a given task. + use ark_ec::{ - CurveConfig, short_weierstrass::{Affine as SWAffine, SWCurveConfig}, twisted_edwards::{Affine as TEAffine, MontCurveConfig, TECurveConfig}, + CurveConfig, }; use ark_ff::{Field, One}; use ark_std::borrow::Cow; -// Constants used in mapping TE form to SW form and vice versa +/// Constants used in mapping TE form to SW form and vice versa. +/// Configuration trait for curves that support mapping between representations. +/// +/// This trait must be implemented for curves that need to be converted between +/// Twisted Edwards, Short Weierstrass, and Montgomery forms. pub trait MapConfig: TECurveConfig + SWCurveConfig + MontCurveConfig { + /// Precomputed value of Montgomery curve parameter A divided by 3. const MONT_A_OVER_THREE: ::BaseField; + + /// Precomputed inverse of Montgomery curve parameter B. const MONT_B_INV: ::BaseField; } -/// Map a a point in Short Weierstrass form into its corresponding point in Twisted Edwards form. +/// Map a point in Short Weierstrass form into its corresponding point in Twisted Edwards form. +/// +/// This function performs the conversion by first mapping from Short Weierstrass to Montgomery form, +/// then from Montgomery to Twisted Edwards form. pub fn sw_to_te(point: &SWAffine) -> Option> { // First map the point from SW to Montgomery // (Bx - A/3, By) @@ -30,7 +45,10 @@ pub fn sw_to_te(point: &SWAffine) -> Option> { Some(TEAffine::new_unchecked(v, w)) } -/// Map a a point in Twisted Edwards form into its corresponding point in Short Weierstrass form. +/// Map a point in Twisted Edwards form into its corresponding point in Short Weierstrass form. +/// +/// This function performs the conversion by first mapping from Twisted Edwards to Montgomery form, +/// then from Montgomery to Short Weierstrass form. pub fn te_to_sw(point: &TEAffine) -> Option> { // Map from TE to Montgomery: (1+y)/(1-y), (1+y)/(x(1-y)) let v_denom = <::BaseField as One>::one() - point.y; @@ -48,11 +66,21 @@ pub fn te_to_sw(point: &TEAffine) -> Option> { Some(SWAffine::new_unchecked(x, y)) } +/// Trait for types that can be converted from/to Short Weierstrass form. +/// +/// This trait provides methods to convert between a type and its Short Weierstrass representation, +/// both for individual points and slices of points. pub trait SWMapping { + /// Convert a Short Weierstrass point to this type. fn from_sw(sw: SWAffine) -> Self; + /// Convert this type to a Short Weierstrass point. fn into_sw(self) -> SWAffine; + /// Convert a slice of this type to a slice of Short Weierstrass points. + /// + /// Returns a borrowed slice if no conversion is needed, or an owned + /// vector if conversion is required. fn to_sw_slice(slice: &[Self]) -> Cow<[SWAffine]> where Self: Sized; @@ -102,11 +130,21 @@ impl SWMapping for TEAffine { } } +/// Trait for types that can be converted from/to Twisted Edwards form. +/// +/// This trait provides methods to convert between a type and its Twisted Edwards representation, +/// both for individual points and slices of points. pub trait TEMapping { + /// Convert a Twisted Edwards point to this type. fn from_te(te: TEAffine) -> Self; + /// Convert this type to a Twisted Edwards point. fn into_te(self) -> TEAffine; + /// Convert a slice of this type to a slice of Twisted Edwards points. + /// + /// Returns a borrowed slice if no conversion is needed, or an owned + /// vector if conversion is required. fn to_te_slice(slice: &[Self]) -> Cow<[TEAffine]> where Self: Sized; From 240ed83fea8da5a75c155870e2a1e41a2725a35b Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 12:41:31 +0200 Subject: [PATCH 06/10] Fmt --- src/lib.rs | 2 +- src/pedersen.rs | 2 +- src/utils/common.rs | 4 ++-- src/utils/te_sw_map.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b54bfa0..2c86af1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -396,7 +396,7 @@ macro_rules! suite_types { mod tests { use super::*; use suites::testing::{Input, Secret}; - use testing::{random_val, TEST_SEED}; + use testing::{TEST_SEED, random_val}; #[test] fn vrf_output_check() { diff --git a/src/pedersen.rs b/src/pedersen.rs index 6b8bd36..a27064a 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -218,7 +218,7 @@ impl Verifier for Public { #[cfg(test)] pub(crate) mod testing { use super::*; - use crate::testing::{self as common, random_val, CheckPoint, SuiteExt, TEST_SEED}; + use crate::testing::{self as common, CheckPoint, SuiteExt, TEST_SEED, random_val}; pub fn prove_verify() { use pedersen::{Prover, Verifier}; diff --git a/src/utils/common.rs b/src/utils/common.rs index 595f098..04ff4bc 100644 --- a/src/utils/common.rs +++ b/src/utils/common.rs @@ -6,8 +6,8 @@ use crate::*; use ark_ec::{ - hashing::curve_maps::elligator2::{Elligator2Config, Elligator2Map}, AffineRepr, + hashing::curve_maps::elligator2::{Elligator2Config, Elligator2Map}, }; use ark_ff::PrimeField; use digest::{Digest, FixedOutputReset}; @@ -113,7 +113,7 @@ where Elligator2Map>: ark_ec::hashing::map_to_curve_hasher::MapToCurve< as AffineRepr>::Group>, { - use ark_ec::hashing::{map_to_curve_hasher::MapToCurveBasedHasher, HashToCurve}; + use ark_ec::hashing::{HashToCurve, map_to_curve_hasher::MapToCurveBasedHasher}; use ark_ff::field_hashers::DefaultFieldHasher; // Domain Separation Tag := "ECVRF_" || h2c_suite_ID_string || suite_string diff --git a/src/utils/te_sw_map.rs b/src/utils/te_sw_map.rs index b90c21e..d9841d2 100644 --- a/src/utils/te_sw_map.rs +++ b/src/utils/te_sw_map.rs @@ -4,9 +4,9 @@ //! allowing operations to be performed in the most convenient form for a given task. use ark_ec::{ + CurveConfig, short_weierstrass::{Affine as SWAffine, SWCurveConfig}, twisted_edwards::{Affine as TEAffine, MontCurveConfig, TECurveConfig}, - CurveConfig, }; use ark_ff::{Field, One}; use ark_std::borrow::Cow; From 76444ced50ca99700298f74a848b137099bcb007 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 12:50:58 +0200 Subject: [PATCH 07/10] Suites docs --- src/suites/baby_jubjub.rs | 2 +- src/suites/bandersnatch.rs | 10 ++++------ src/suites/ed25519.rs | 2 +- src/suites/jubjub.rs | 2 +- src/suites/mod.rs | 24 ++++++++++++++++++++++-- src/suites/secp256r1.rs | 2 +- 6 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/suites/baby_jubjub.rs b/src/suites/baby_jubjub.rs index 908e2d4..565d2dd 100644 --- a/src/suites/baby_jubjub.rs +++ b/src/suites/baby_jubjub.rs @@ -1,4 +1,4 @@ -//! `ECVRF Baby-JubJub SHA-512 Try and Increment H2C` suite. +//! ECVRF Baby-JubJub SHA-512 TAI suite //! //! Configuration: //! diff --git a/src/suites/bandersnatch.rs b/src/suites/bandersnatch.rs index 62f2865..1561617 100644 --- a/src/suites/bandersnatch.rs +++ b/src/suites/bandersnatch.rs @@ -1,4 +1,4 @@ -//! `ECVRF Bandersnatch SHA-512 Elligator2` suite. +//! # ECVRF Bandersnatch SHA-512 Elligator2 suite //! //! Configuration: //! @@ -141,10 +141,8 @@ pub(crate) mod tests { fn elligator2_hash_to_curve() { use crate::testing::CheckPoint; let raw = crate::testing::random_vec(42, None); - assert!( - ThisSuite::data_to_point(&raw) - .map(|p| p.check(true).ok()) - .is_some() - ); + assert!(ThisSuite::data_to_point(&raw) + .map(|p| p.check(true).ok()) + .is_some()); } } diff --git a/src/suites/ed25519.rs b/src/suites/ed25519.rs index 09d1dbd..c074b7a 100644 --- a/src/suites/ed25519.rs +++ b/src/suites/ed25519.rs @@ -1,4 +1,4 @@ -//! `ECVRF-EDWARDS25519-SHA-512-TAI` suite. +//! # ECVRF Ed25519 SHA-512 TAI suite //! //! Configuration (RFC-9381 with some compromises): //! diff --git a/src/suites/jubjub.rs b/src/suites/jubjub.rs index 010128b..fdf00e2 100644 --- a/src/suites/jubjub.rs +++ b/src/suites/jubjub.rs @@ -1,4 +1,4 @@ -//! `ECVRF JubJub SHA-512 Try and Increment H2C` suite. +//! # ECVRF JubJub SHA-512 TAI suite //! //! Configuration: //! diff --git a/src/suites/mod.rs b/src/suites/mod.rs index 55bbead..af2dbe8 100644 --- a/src/suites/mod.rs +++ b/src/suites/mod.rs @@ -1,6 +1,26 @@ -//! Featured suites. +//! # Cipher Suites //! -//! Each is conditionally compiled based on its corresponding feature flag. +//! This module provides pre-configured cipher suites for various elliptic curves. +//! Each suite is conditionally compiled based on its corresponding feature flag. +//! +//! ## Available Suites +//! +//! - **Ed25519**: Edwards curve with SHA-512 hash function and Try-And-Increment (TAI) +//! hash-to-curve method. Supports IETF and Pedersen VRF schemes. +//! +//! - **Secp256r1**: NIST P-256 curve with SHA-256 hash function and TAI hash-to-curve +//! method. Supports IETF and Pedersen VRF schemes. Uses SEC1 point encoding. +//! +//! - **Bandersnatch**: Edwards curve defined over the BLS12-381 scalar field with +//! SHA-512 hash function. Supports IETF, Pedersen, and Ring VRF schemes. +//! Available in both Edwards and Short Weierstrass forms. +//! +//! - **JubJub**: Edwards curve defined over the BLS12-381 scalar field with +//! SHA-512 hash function. Supports IETF, Pedersen, and Ring VRF schemes. +//! +//! - **Baby-JubJub**: Edwards curve defined over the BN254 scalar field with +//! SHA-512 hash function. Supports IETF, Pedersen, and Ring VRF schemes. +//! Optimized for Ethereum compatibility. #[cfg(test)] pub(crate) mod testing; diff --git a/src/suites/secp256r1.rs b/src/suites/secp256r1.rs index 907b7df..bfaf1ca 100644 --- a/src/suites/secp256r1.rs +++ b/src/suites/secp256r1.rs @@ -1,4 +1,4 @@ -//! `ECVRF-P256-SHA256-TAI` suite. +//! # ECVRF P256 SHA-256 TAI suite //! //! Configuration (RFC-9381): //! From 8b8afe0b978bbdaac93ad818f554a23b14e8b044 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 12:51:57 +0200 Subject: [PATCH 08/10] Fmt --- src/suites/bandersnatch.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/suites/bandersnatch.rs b/src/suites/bandersnatch.rs index 1561617..9427a93 100644 --- a/src/suites/bandersnatch.rs +++ b/src/suites/bandersnatch.rs @@ -141,8 +141,10 @@ pub(crate) mod tests { fn elligator2_hash_to_curve() { use crate::testing::CheckPoint; let raw = crate::testing::random_vec(42, None); - assert!(ThisSuite::data_to_point(&raw) - .map(|p| p.check(true).ok()) - .is_some()); + assert!( + ThisSuite::data_to_point(&raw) + .map(|p| p.check(true).ok()) + .is_some() + ); } } From 78e1368b7150f36792dc7145ba310874f5834a76 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 12:54:10 +0200 Subject: [PATCH 09/10] Clippy --- src/utils/common.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/common.rs b/src/utils/common.rs index 04ff4bc..471f7c8 100644 --- a/src/utils/common.rs +++ b/src/utils/common.rs @@ -6,8 +6,8 @@ use crate::*; use ark_ec::{ - AffineRepr, hashing::curve_maps::elligator2::{Elligator2Config, Elligator2Map}, + AffineRepr, }; use ark_ff::PrimeField; use digest::{Digest, FixedOutputReset}; @@ -94,7 +94,7 @@ pub fn hash_to_curve_tai_rfc_9381(data: &[u8]) -> Option>: ark_ec::hashing::map_to_curve_hasher::MapToCurve< as AffineRepr>::Group>, { - use ark_ec::hashing::{HashToCurve, map_to_curve_hasher::MapToCurveBasedHasher}; + use ark_ec::hashing::{map_to_curve_hasher::MapToCurveBasedHasher, HashToCurve}; use ark_ff::field_hashers::DefaultFieldHasher; // Domain Separation Tag := "ECVRF_" || h2c_suite_ID_string || suite_string From 60346a9cb725420a4fecad7b08bca45252cbca21 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 May 2025 12:56:39 +0200 Subject: [PATCH 10/10] Fmt --- src/utils/common.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/common.rs b/src/utils/common.rs index 471f7c8..913721e 100644 --- a/src/utils/common.rs +++ b/src/utils/common.rs @@ -6,8 +6,8 @@ use crate::*; use ark_ec::{ - hashing::curve_maps::elligator2::{Elligator2Config, Elligator2Map}, AffineRepr, + hashing::curve_maps::elligator2::{Elligator2Config, Elligator2Map}, }; use ark_ff::PrimeField; use digest::{Digest, FixedOutputReset}; @@ -113,7 +113,7 @@ where Elligator2Map>: ark_ec::hashing::map_to_curve_hasher::MapToCurve< as AffineRepr>::Group>, { - use ark_ec::hashing::{map_to_curve_hasher::MapToCurveBasedHasher, HashToCurve}; + use ark_ec::hashing::{HashToCurve, map_to_curve_hasher::MapToCurveBasedHasher}; use ark_ff::field_hashers::DefaultFieldHasher; // Domain Separation Tag := "ECVRF_" || h2c_suite_ID_string || suite_string