Skip to content

Commit

Permalink
Merge pull request #91 from davxy/davxy-tweaks
Browse files Browse the repository at this point in the history
Cleanup
  • Loading branch information
davxy authored Apr 3, 2024
2 parents dbf3fda + 2fc6d26 commit 03b99dc
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 274 deletions.
11 changes: 2 additions & 9 deletions Specification.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,9 @@ authors = ["Alistair, Davide, Jeff, Syed, Sergey"]
template = "specification_template.md"

[sections]
# DLEQ VRF
dleq-vrf-preliminaries = "dleq_vrf/src/lib.rs"
## VRF
vrf = "dleq_vrf/src/vrf.rs"
### VRF Keys
vrf-keys = "dleq_vrf/src/keys.rs"

## Thin VRF

# DLEQ VRF
dleq-vrf-preliminaries = "dleq_vrf/src/lib.rs"
## Pedersen VRF
pedersen-vrf = "dleq_vrf/src/pedersen.rs"

# Bandersnatch VRF
9 changes: 1 addition & 8 deletions dleq_vrf/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ use crate::{
};


//~ #### Public key \
//~ \
//~ A Public key of a VRF is a point on an Elliptic Curve $E$. \
#[derive(Debug,Clone,Eq,Hash,CanonicalSerialize,CanonicalDeserialize)] // Copy, PartialOrd, Ord, Hash,
#[derive(Debug, Clone, Eq, Hash, CanonicalSerialize, CanonicalDeserialize)] // Copy, PartialOrd, Ord, Hash,
#[repr(transparent)]
pub struct PublicKey<C: AffineRepr>(pub C);

Expand All @@ -37,9 +34,6 @@ impl<C: AffineRepr> PartialEq for PublicKey<C> {
}
}

//~ Public key is represented in Affine form and is serialized using Arkwork compressed serialized
//~ format.
//
/// Arkworks' own serialization traits should be preferred over these.
impl<C: AffineRepr> PublicKey<C> {
pub fn update_digest(&self, h: &mut impl Update) {
Expand Down Expand Up @@ -259,4 +253,3 @@ impl<K: AffineRepr> SecretKey<K> {
}
*/
}

83 changes: 43 additions & 40 deletions dleq_vrf/src/vrf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@
// Authors:
// - Jeffrey Burdges <jeff@web3.foundation>

//~ **Definition**: A *verifiable random function with auxiliary data (VRF-AD)* can be described with three functions:
//~ **Definition**: A *verifiable random function with additional data (VRF-AD)*
//~ can be described with four functions:
//~
//~ - $VRF.KeyGen: () \mapsto (pk,sk)$ where $pk$ is a public key and $sk$ is its corresponding secret key.
//~ - $VRF.Sign : (sk,msg,aux) \mapsto \sigma$ takes a secret key $sk$, an input $msg$, and auxiliary data $aux$, and then returns a VRF signature $\sigma$.
//~ - $VRF.Eval : (sk, msg) \mapsto Out$ takes a secret key $sk$ and an input $msg$, and then returns a VRF output $Out$.
//~ - $VRF.Verify: (pk,msg,aux,\sigma)\mapsto (Out|prep)$ for a public key pk, an input msg, and auxiliary data aux, and then returns either an output $Out$ or else failure $perp$.
//~
//~ **Definition**: For an elliptic curve $E$ defined over finite field $F$ with large prime subgroup $G$ generated by point $g$, we call a VRF, EC-VRF is VRF-AD where $pk = sk.g$ and $VRF.Sign$ is an elliptic curve signature scheme.
//~ - $VRF.KeyGen: () \mapsto (pk,sk)$ where $pk$ is a public key and $sk$ is
//~ its corresponding secret key.
//~ - $VRF.Sign : (sk,msg,ad) \mapsto \pi$ takes a secret key $sk$, an input $msg$,
//~ and additional data $ad$, and returns a VRF signature $\pi$.
//~ - $VRF.Eval : (sk, msg) \mapsto Out$ takes a secret key $sk$ and an input $msg$,
//~ and returns a VRF output $out$.
//~ - $VRF.Verify: (pk,msg,aux,\pi) \mapsto (out|prep)$ for a public key $pk$,
//~ an input $msg$, and additional data $ad$, and then returns either an output
//~ $out$ or else failure $perp$.
//~
//~ **Definition**: For an elliptic curve $E$ defined over finite field $F$ with
//~ large prime subgroup $G$ generated by point $g$, an EC-VRF is VRF-AD
//~ where $pk = sk \cdot g$ and $VRF.Sign$ is based on an elliptic curve signature
//~ scheme.
//~
//~ All VRFs described in this specification are EC-VRF.

//! All VRFs expect a point on the curve as their input.
//~
//! All VRFs expect a point on the curve as their input.
//! ### VRF input and output handling
//!
//! We caution that ring VRFs based upon DLEQ proofs like ours require
Expand All @@ -30,20 +39,23 @@ use crate::{Transcript,IntoTranscript,transcript::AsLabel,SecretKey};

use core::borrow::{Borrow}; // BorrowMut

//~ For input $msg$ and $aux$ auxilary data first we compute the $VRFInput$ which is a point on elliptic curve $E$ as follows:
//~ For input $msg$ and $ad$ additional data first we compute the $VRFInput$
//~ which is a point on elliptic curve $E$ as follows:
//
//~ $$ t \leftarrow Transcript(msg) $$
//~ $$ VRFiput := H2C(challange(t, "vrf-input") $$
//~ $$ t \leftarrow Transcript(msg) $$
//~ $$ VRFInput := H2C(challange(t, "vrf-input") $$
//~
//~ where
//~ - $transcript$ function is described in [[ark-transcript]] section.
//~ - $H2C: B \rightarrow G$ is a hash to curve function correspond to curve $E$ specified in Section [[hash-to-curve]] for the specific choice of $E$
//~
//~ Where:
//~ - $transcript$ function is described in [[ark-transcript]] section.
//~ - $H2C: B \rightarrow G$ is a hash to curve function correspond
//~ to curve $E$ specified in Section [[hash-to-curve]] for the specific choice of $E$
//~
/// Create VRF input points
///
/// You select your own hash-to-curve by implementing this trait
/// upon your own wrapper type.
///
///
/// Instead of our method being polymorphic, we impose the type parameter
/// in the trait because doing so simplifies the type annotations.
pub trait IntoVrfInput<C: AffineRepr> {
Expand Down Expand Up @@ -81,28 +93,25 @@ where C: AffineRepr, H2C: HashToCurve<<C as AffineRepr>::Group>,
Ok(VrfInput( H2C::new(domain.as_label())?.hash(message)? ))
}


/// Actual VRF input, consisting of an elliptic curve point.
///
//~ ### VRF Input
//~ The VRF input ultimately is a point on the elliptic curve
//~ as out put of hash of the transcript using arkworks chosen hash
//~ for the given curve.
//~
//~ VRF Input point should always be created locally, either as a hash-to-cuve
//~ output of the transcripto or ocasionally some base point.
//~ It should never be sent over the wire nor deserialized???Do you mean serialized?
//~
//~ The VRF Input is a point on the elliptic curve E and generated
//~ as output of the Elligator 2 hash-to-curve algorithm
//~ as described by section 6.8.2 of [RFC9380](https://datatracker.ietf.org/doc/rfc9380/).
//~ The algorithm yields a point which is inside the prime order
//~ subgroup of E.
//~
/// `VrfInput` should always be consructed inside the prime order
/// subgroup, as otherwise risks leaking secret key material.
///
///
/// We do not enforce that key material be hashed in hash-to-curve,
/// so our VRF pre-outputs and signatures reveal VRF outputs for
/// algebraically related secret keys. We need this for ring VRFs
/// but this makes insecure the soft derivations in hierarchical
/// key derivation (HDKD) schemes.
///
///
/// As a defense in depth, we suggest thin VRF usages hash their
/// public, given some broken applications might do soft derivations
/// anyways.
Expand Down Expand Up @@ -137,8 +146,11 @@ impl<K: AffineRepr> SecretKey<K> {
}

//~ ### VRF Preoutput and Output
//~ **Definition**: *VRF pre-output* is defined to be a point in $E$ in serialized affine representation.
//~
//~
//~ **Definition**: *VRF pre-output* is generated using VRF input point as:
//~
//~ $$ PreOutput \leftarrow sk \cdot VrfInput $$
//~
/// VRF pre-output, possibly unverified.
#[derive(Debug,Copy,Clone,PartialEq,Eq,CanonicalSerialize,CanonicalDeserialize)] // Copy, Default, PartialOrd, Ord, Hash
#[repr(transparent)]
Expand Down Expand Up @@ -192,11 +204,7 @@ pub fn collect_preoutputs_vec<C: AffineRepr>(ios: &[VrfInOut<C>]) -> Vec<VrfPreO
).collect::<Vec<VrfPreOut<C>>>()
}

//~ **Definition**: *VRF InOut* is defined as a pair as follows:
//~ $$(VRF Input, VRF Preoutput)$$
/// VRF input and pre-output paired together, possibly unverified.
///
///
#[derive(Debug,Copy,Clone,CanonicalSerialize)] // CanonicalDeserialize, PartialEq,Eq, PartialOrd, Ord, Hash
pub struct VrfInOut<C: AffineRepr> {
/// VRF input point
Expand All @@ -206,11 +214,9 @@ pub struct VrfInOut<C: AffineRepr> {
}

impl<C: AffineRepr> VrfInOut<C> {
//~ **Definition**: *VRF output* is generated using VRF preoutput:
//~ $$ t \leftarrow Transcript(Domain) $$
//~ $$ append(t, "VrfOutput") $$
//~ $$ append(t, cofactor * VRFpreout) $$
//~ $$ VRFoutput \leftarrow t.challenge("") $$
//~ **Definition**: *VRF output* is generated using *VRF pre-output* point as:
//~ $$ VrfOutput \leftarrow Hash("vrfoutput", Encode(PreOutput)) $$
//~

/// Append to VRF output transcript, suitable for producing VRF output.
///
Expand Down Expand Up @@ -338,6 +344,3 @@ where
#[cfg(test)]
mod tests {
}



121 changes: 48 additions & 73 deletions spec/specification.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,66 @@
# Bandersnatch VRFs

## VRF
## Introduction

**Definition**: A *verifiable random function with additional data (VRF-AD)*
can be described with four functions:

- $VRF.KeyGen: () \mapsto (pk,sk)$ where $pk$ is a public key and $sk$ is
its corresponding secret key.
- $VRF.Sign : (sk,msg,ad) \mapsto \pi$ takes a secret key $sk$, an input $msg$,
and additional data $ad$, and returns a VRF signature $\pi$.
- $VRF.Eval : (sk, msg) \mapsto Out$ takes a secret key $sk$ and an input $msg$,
and returns a VRF output $out$.
- $VRF.Verify: (pk,msg,aux,\pi) \mapsto (out|prep)$ for a public key $pk$,
an input $msg$, and additional data $ad$, and then returns either an output
$out$ or else failure $perp$.

**Definition**: For an elliptic curve $E$ defined over finite field $F$ with
large prime subgroup $G$ generated by point $g$, an EC-VRF is VRF-AD
where $pk = sk \cdot g$ and $VRF.Sign$ is based on an elliptic curve signature
scheme.

**Definition**: A *verifiable random function with auxiliary data (VRF-AD)* can be described with three functions:

- $VRF.KeyGen: () \mapsto (pk,sk)$ where $pk$ is a public key and $sk$ is its corresponding secret key.
- $VRF.Sign : (sk,msg,aux) \mapsto \sigma$ takes a secret key $sk$, an input $msg$, and auxiliary data $aux$, and then returns a VRF signature $\sigma$.
- $VRF.Eval : (sk, msg) \mapsto Out$ takes a secret key $sk$ and an input $msg$, and then returns a VRF output $Out$.
- $VRF.Verify: (pk,msg,aux,\sigma)\mapsto (Out|prep)$ for a public key pk, an input msg, and auxiliary data aux, and then returns either an output $Out$ or else failure $perp$.
All VRFs described in this specification are EC-VRF.

**Definition**: For an elliptic curve $E$ defined over finite field $F$ with large prime subgroup $G$ generated by point $g$, we call a VRF, EC-VRF is VRF-AD where $pk = sk.g$ and $VRF.Sign$ is an elliptic curve signature scheme.
For input $msg$ and $ad$ additional data first we compute the $VRFInput$
which is a point on elliptic curve $E$ as follows:
$$ t \leftarrow Transcript(msg) $$
$$ VRFInput := H2C(challange(t, "vrf-input") $$

All VRFs described in this specification are EC-VRF.
For input $msg$ and $aux$ auxilary data first we compute the $VRFInput$ which is a point on elliptic curve $E$ as follows:
$$ t \leftarrow Transcript(msg) $$
$$ VRFiput := H2C(challange(t, "vrf-input") $$

where
- $transcript$ function is described in [[ark-transcript]] section.
- $H2C: B \rightarrow G$ is a hash to curve function correspond to curve $E$ specified in Section [[hash-to-curve]] for the specific choice of $E$
Where:
- $transcript$ function is described in [[ark-transcript]] section.
- $H2C: B \rightarrow G$ is a hash to curve function correspond
to curve $E$ specified in Section [[hash-to-curve]] for the specific choice of $E$

### VRF Input
The VRF input ultimately is a point on the elliptic curve
as out put of hash of the transcript using arkworks chosen hash
for the given curve.

VRF Input point should always be created locally, either as a hash-to-cuve
output of the transcripto or ocasionally some base point.
It should never be sent over the wire nor deserialized???Do you mean serialized?

The VRF Input is a point on the elliptic curve E and generated
as output of the Elligator 2 hash-to-curve algorithm
as described by section 6.8.2 of [RFC9380](https://datatracker.ietf.org/doc/rfc9380/).
The algorithm yields a point which is inside the prime order
subgroup of E.

### VRF Preoutput and Output
**Definition**: *VRF pre-output* is defined to be a point in $E$ in serialized affine representation.

**Definition**: *VRF InOut* is defined as a pair as follows:
$$(VRF Input, VRF Preoutput)$$
**Definition**: *VRF output* is generated using VRF preoutput:
$$ t \leftarrow Transcript(Domain) $$
$$ append(t, "VrfOutput") $$
$$ append(t, cofactor * VRFpreout) $$
$$ VRFoutput \leftarrow t.challenge("") $$
**Definition**: *VRF pre-output* is generated using VRF input point as:

$$ PreOutput \leftarrow sk \cdot VrfInput $$

### VRF Key
**Definition**: *VRF output* is generated using *VRF pre-output* point as:
$$ VrfOutput \leftarrow Hash("vrfoutput", Encode(PreOutput)) $$

#### Public key \
\
A Public key of a VRF is a point on an Elliptic Curve $E$. \
Public key is represented in Affine form and is serialized using Arkwork compressed serialized
format.


## IETF VRF

Refer to [RFC-9381](https://www.rfc-editor.org/rfc/rfc9381) for the details.
Definition of a VRF based on the IETF [RFC-9381](https://www.rfc-editor.org/rfc/rfc9381).

All the details specified by the RFC applies with the additional capability to add additional
data (`ad`) as per definition of EC-VRF we've given. In particular the step 5 of section
5.4.3 is defined as:

str = str || ad || challenge_generation_domain_separator_back

### Bandersnatch Cipher Suite Configuration

Expand Down Expand Up @@ -100,9 +107,10 @@ Configuration follows the RFC-9381 suite specification guidelines.
* The hash function Hash is SHA-512 as specified in
[RFC6234](https://www.rfc-editor.org/rfc/rfc6234), with hLen = 64.

* The ECVRF_encode_to_curve function is as specified in
Section 5.4.1.2, with `h2c_suite_ID_string` = `"BANDERSNATCH_XMD:BLAKE2b_ELL2_RO_"`.
The suite is defined in Section 8.5 of [RFC9380](https://datatracker.ietf.org/doc/rfc9380/).
* The `ECVRF_encode_to_curve` function (*Elligator2*) is as specified in
Section 5.4.1.2, with `h2c_suite_ID_string` = `"BANDERSNATCH_XMD:SHA-512_ELL2_RO_"`.
The suite must be interpreted as defined by Section 8.5 of [RFC9380](https://datatracker.ietf.org/doc/rfc9380/)
and using the domain separation tag `DST = "ECVRF_" || h2c_suite_ID_string || suite_string`.

## Pedersen VRF

Expand Down Expand Up @@ -181,36 +189,3 @@ $z2 \leftarrow ClearCofactor(z1)$

---


## VRF input

Procedure to map arbitrary user input to a point follows the `hash_to_curve`
procedure described by RFC9380.

Suite_ID: "bandersnatch_XMD:SHA-512_ELL2_RO_"

See [ArkTranscript](TODO) for details.

### From transcript to point

You need to call challenge and add b"vrf-input" to it. getting random byte (some hash?)
then hash to curve it.

## Transcript

A Shake-128 based transcript construction which implements the Fiat-Shamir
transform procedure.

We do basic domain separation using postfix writes of the lengths of written
data (as opposed to the prefix writes by [Merlin](https://merlin.cool)
`TupleHash` from [SP 800-185](https://csrc.nist.gov/pubs/sp/800/185/final)).

H(item_1, item_2, ..., item_n)

Represents the application of shake-128 to the concatenation of the serialization of each item
followed by the serialization of the length of each objects, as a 32-bit unsigned integer.

bytes = encode(item_1) || encode(length(item_1)) || .. || encode(item_n) || encode(length(item_n))
Shake128(bytes)

The length of each item should be less than 2^31.
Binary file modified spec/specification.pdf
Binary file not shown.
Loading

0 comments on commit 03b99dc

Please sign in to comment.