Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mmaker committed Feb 1, 2024
1 parent 78958e1 commit 46d68a3
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 38 deletions.
2 changes: 1 addition & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[build]
rustdocflags = "--html-in-header doc/katex-header.html"
rustdocflags = "--html-in-header doc/katex-header.html"
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,26 @@ Nimue: a Fiat-Shamir library
**This library has not been externally reviewed yet and shouldn't be considered ready for deployments.**

Nimue is a hash-agnostic library that believes in random oracles.
It built on the top of the SAFE framework and provides an API for generating the verifier's and prover's random coins.
It facilitates the writing of multi-round public coin protocols.
Built on the top of the SAFE framework and provides an API for generating the verifier's and prover's random coins.

# Features
It provides the following features:

- **Automatic transcript generation**: nimue comes with batteries included for serializing/deserializing algebraic elements such as field/group elements in [Arkworks](https://github.com/arkworks-rs/algebra) and [Zkcrypto](https://github.com/zkcrypto/group). Users can build the top of it via extension trait.

- **Support custom hash function**, including algebraic hashes.
To build a secure Fiat-Shamir transform, the minimal requirement is a permutation function over some field,
be it $\mathbb{F}_{2^8}$ or any large-characteristic prime field $\mathbb{F}_p$.

- **Retro-compatibility** with MD hashes.
We have a legacy interface for `sha2`, `blake2`, and any hash function that satisfies the [`digest::Digest`] trait.

- **Preprocessing**.
In recursive SNARKs, minimizing the number of hash invocations
while maintaining security is crucial. We offer tools for preprocessing the Transcript (i.e., the state of the Fiat-Shamir transform) to achieve this goal.

- **Private randomness generation**.
It is vital to avoid providing two different challenges for the same prover message. We do our best to avoid it by tying down the prover randomness to the protocol transcript, without making the proof deterministic.

Check out the [documentation](https://docs.rs/nimue/latest/nimue/) and some [`examples/`](https://github.com/mmaker/nimue/tree/main/examples).
3 changes: 2 additions & 1 deletion examples/bulletproof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ trait BulletproofIOPattern<G: CurveGroup> {

impl<G> BulletproofIOPattern<G> for IOPattern
where
G: CurveGroup, IOPattern: GroupIOPattern<G> + FieldIOPattern<G::ScalarField>,
G: CurveGroup,
IOPattern: GroupIOPattern<G> + FieldIOPattern<G::ScalarField>,
{
/// The IO of the bulletproof statement
fn bulletproof_statement(self) -> Self {
Expand Down
10 changes: 8 additions & 2 deletions src/iopattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ impl<H: DuplexHash<U>, U: Unit> IOPattern<H, U> {
pub fn absorb(self, count: usize, label: &str) -> Self {
assert!(count > 0, "Count must be positive");
assert!(!label.contains(SEP_BYTE));
assert!(label.is_empty() || label[..1].parse::<u8>().is_err());
assert!(match label.chars().next() {
Some(char) => !char.is_ascii_digit(),
None => true,
});

Self::from_string(self.io + SEP_BYTE + &format!("A{}", count) + label)
}
Expand All @@ -98,7 +101,10 @@ impl<H: DuplexHash<U>, U: Unit> IOPattern<H, U> {
pub fn squeeze(self, count: usize, label: &str) -> Self {
assert!(count > 0, "Count must be positive");
assert!(!label.contains(SEP_BYTE));
assert!(label.is_empty() || label[..1].parse::<u8>().is_err());
assert!(match label.chars().next() {
Some(char) => !char.is_ascii_digit(),
None => true,
});

Self::from_string(self.io + SEP_BYTE + &format!("S{}", count) + label)
}
Expand Down
54 changes: 23 additions & 31 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,10 @@
//! of random coins for the verifier.
//! It is inspired by the [SAFE] API, with minor variations.
//!
//! # Features
//!
//! Nimue facilitates the writing of multi-round public coin protocols.
//! It provides the following features:
//! - **Automatic transcript generation**: nimue comes with batteries included for serializing/deserializing algebraic elements such as field/group elements in [Arkworks](https://github.com/arkworks-rs/algebra) and [Zkcrypto](https://github.com/zkcrypto/group). Users can build the top of it via extension trait.
//! - **Support custom hash function**, including algebraic hashes.
//! To build a secure Fiat-Shamir transform, the minimal requirement is a permutation function over some field,
//! be it $\mathbb{F}_{2^8}$ or any large-characteristic prime field $\mathbb{F}_p$.
//! - **Retro-compatibility** with MD hashes.
//! We have a legacy interface for `sha2`, `blake2`, and any hash function that satisfies the [`digest::Digest`] trait.
//! - **Preprocessing**.
//! In recursive SNARKs, minimizing the number of hash invocations
//! while maintaining security is crucial. We offer tools for preprocessing the Transcript (i.e., the state of the Fiat-Shamir transform) to achieve this goal.
//! - **Private randomness generation**.
//! It is vital to avoid providing two different challenges for the same prover message. We do our best to avoid it by tying down the prover randomness to the protocol transcript, without making the proof deterministic.
//!
//! # Overview
//!
//! The library does three things:
//! The library does two things:
//!
//! - Assist in the construction of a protocol transcript for a public-coin zero-knowledge proof ([`Arthur`]),
//! - Assist in the deserialization and verification of a public-coin protocol ([`Merlin`]).
Expand All @@ -51,10 +36,18 @@
//! .squeeze(10, "second");
//! assert_eq!(io.as_bytes(), "👩‍💻🥷🏻👨‍💻 building 🔐🔒🗝️\0A10first\0S10second".as_bytes())
//! ```
//! An [`IOPattern`] is a UTF8-encoded string wrapper. Absorptions are denoted as `format!(A{}, length)` and
//! squeezes as `format!(S{}, length)`. A label is added at the end of the string, meant to describe the *type* and
//! An [`IOPattern`] is a UTF8-encoded string wrapper. Absorptions are marked by `A` and
//! squeezes by `S`, followed by the respective length
//! (note: length is expressed in terms of [`hash::Unit`], native elements over which the hash function works).
//! A label is added at the end of each absorb/squeeze, to describe the *type* and
//! *the variable* as used in the protocol. Operations are separated by a NULL byte and therefore labels cannot contain
//! NULL bytes themselves, nor start with an ASCII digit.
//! NULL bytes themselves, nor they can start with an ASCII digit.
//!
//! # Batteries included
//! The library comes with support for algebraic objects over arkworks and zkcrypto:
//! - with feature flag `--feature=ark`, the module [`plugins::ark`] provides extension traits for arkworks fields and groups;

Check warning on line 48 in src/lib.rs

View workflow job for this annotation

GitHub Actions / deploy

unresolved link to `plugins::ark`
//! - with feature flag `--feature=group`, the module [`plugins::group`] provides extension traits for zkcrypto's field and group traits.

Check warning on line 49 in src/lib.rs

View workflow job for this annotation

GitHub Actions / deploy

unresolved link to `plugins::group`
//! See the [`plugins`] module for more information.

Check warning on line 50 in src/lib.rs

View workflow job for this annotation

GitHub Actions / deploy

unresolved link to `plugins`
//!
//!
//! # Protocol transcripts
Expand All @@ -65,28 +58,27 @@
//!
//! ```
//! use nimue::{IOPattern, Arthur};
//! use nimue::hash::Keccak;
//! use nimue::traits::*;
//! use nimue::*;
//! use rand::Rng;
//!
//! // create a new protocol that will absorb 1 byte and squeeze 16 bytes.
//! // by default we use keccak, but things like `DigestBridge<sha2::Sha256>` will work too.
//! let io = IOPattern::<Keccak>::new("example-protocol").absorb(1, "send").squeeze(16, "receive");
//! // Create a new protocol that will absorb 1 byte and squeeze 16 bytes.
//! let io = IOPattern::<DefaultHash>::new("example-protocol 🤌").absorb(1, "↪️").squeeze(16, "↩️");
//! let mut arthur = io.to_arthur();
//! // the prover sends the byte 0x42.
//! arthur.add_bytes(&[0x42]).expect("Absorbing one byte");
//! // the prover receive a 128-bit challenge.
//! // The prover sends the byte 0x42.
//! arthur.add_bytes(&[0x42]).unwrap();
//! // The prover receive a 128-bit challenge.
//! let mut chal = [0u8; 16];
//! arthur.fill_challenge_bytes(&mut chal).expect("Squeezing 128 bits");
//! arthur.fill_challenge_bytes(&mut chal).unwrap();
//! // The transcript is recording solely the bytes sent by the prover so far.
//! assert_eq!(arthur.transcript(), [0x42]);
//! // generate some private randomness bound to the protocol transcript.
//! // Generate some private randomness bound to the protocol transcript.
//! let private = arthur.rng().gen::<[u8; 2]>();
//!
//! assert_eq!(arthur.transcript(), [0x42]);
//! ```
//!
//! (Note: Nimue provides aliases [`DefaultHash`] and [`DefaultRng`] mapping to secure hash functions and random number generators).
//! An [`Arthur`] instance can generate public coin (via a [`Safe`] instance) and private coins.
//! An [`Arthur`] instance can generate public coins (via a [`Safe`] instance) and private coins.
//! Private coins are generated with a sponge that absorbs whatever the public sponge absorbs, and is seeded by a cryptographic random number generator throughout the protocol by the prover.
//! This way, it is really hard to produce two different challenges for the same prover message.
//!
Expand All @@ -97,7 +89,7 @@
//! use nimue::traits::*;
//! use rand::{Rng, rngs::OsRng};
//!
//! let io = IOPattern::<Keccak>::new("example-protocol").absorb(1, "inhale").squeeze(16, "exhale");
//! let io = IOPattern::<Keccak>::new("example-protocol 🧀").absorb(1, "in 🍽️").squeeze(16, "out 🤮");
//! let transcript = [0x42];
//! let mut merlin = io.to_merlin(&transcript);
//!
Expand Down
1 change: 0 additions & 1 deletion src/plugins/ark/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
//! ) -> ProofResult<&[u8]>
//! where
//! G: CurveGroup,
//! Arthur: GroupWriter<G> + FieldChallenges<G::ScalarField>,
//! {
//! let k = G::ScalarField::rand(arthur.rng());
//! arthur.add_points(&[G::generator() * k])?;
Expand Down
1 change: 0 additions & 1 deletion src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::errors::IOPatternError;
use crate::Unit;

pub trait UnitTranscript<U: Unit> {

fn public_units(&mut self, input: &[U]) -> Result<(), IOPatternError>;

fn fill_challenge_units(&mut self, output: &mut [U]) -> Result<(), IOPatternError>;
Expand Down

0 comments on commit 46d68a3

Please sign in to comment.