Skip to content

Commit

Permalink
Simpler Arthur API to work with algebraic hashes.
Browse files Browse the repository at this point in the history
  • Loading branch information
mmaker committed Jan 30, 2024
1 parent eab06a1 commit d726f04
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 32 deletions.
16 changes: 7 additions & 9 deletions examples/schnorr_algebraic_hash.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/// This code is pretty much the same as the one in `schnorr.rs`,
/// except that
/// except for minor changes in order to work with algebraic hashes
/// over the scalar field of BLS12-381.
use ark_ec::{CurveGroup, PrimeGroup};
use ark_ff::PrimeField;
use ark_std::UniformRand;
use nimue::plugins::ark::*;

use rand::{rngs::OsRng, CryptoRng, RngCore};

/// Extend the IO pattern with the Schnorr protocol.
trait SchnorrIOPattern<G: CurveGroup> {
/// Adds the entire Schnorr protocol to the IO pattern (statement and proof).
Expand Down Expand Up @@ -34,7 +33,7 @@ where
/// a secret key `sk` in $\mathbb{Z}_p$
/// and its respective public key `pk` in $\mathbb{G}$.
fn keygen<G: CurveGroup>() -> (G::ScalarField, G) {
let sk = G::ScalarField::rand(&mut OsRng);
let sk = G::ScalarField::rand(&mut nimue::DefaultRng::default());
let pk = G::generator() * sk;
(sk, pk)
}
Expand All @@ -45,10 +44,10 @@ fn keygen<G: CurveGroup>() -> (G::ScalarField, G) {
/// - the secret key $x \in \mathbb{Z}_p$
/// It returns a zero-knowledge proof of knowledge of `x` as a sequence of bytes.
#[allow(non_snake_case)]
fn prove<G, H, U, R>(
fn prove<G, H, U>(
// the hash function `H` works over bytes.
// Algebraic hashes over a particular domain can be denoted with an additional type argument implementing `nimue::Unit`.
arthur: &mut Arthur<H, R, U>,
arthur: &mut Arthur<H, U>,
// the generator
P: G,
// the secret key
Expand All @@ -57,10 +56,9 @@ fn prove<G, H, U, R>(
where
U: Unit,
G::BaseField: PrimeField,
R: CryptoRng + RngCore,
H: DuplexHash<U>,
G: CurveGroup,
Arthur<H, R, U>: GroupWriter<G> + FieldWriter<G::BaseField> + ByteChallenges,
Arthur<H, U>: GroupWriter<G> + FieldWriter<G::BaseField> + ByteChallenges,
{
// `Arthur` types implement a cryptographically-secure random number generator that is tied to the protocol transcript
// and that can be accessed via the `rng()` funciton.
Expand Down Expand Up @@ -152,7 +150,7 @@ fn main() {
let (x, X) = keygen();

// Create the prover transcript, add the statement to it, and then invoke the prover.
let mut arthur = Arthur::<H, _, U>::new(&io, OsRng);
let mut arthur = io.to_arthur();
arthur.public_points(&[P, X]).unwrap();
arthur.ratchet().unwrap();
let proof = prove(&mut arthur, P, x).expect("Invalid proof");
Expand Down
37 changes: 28 additions & 9 deletions src/arthur.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::{DefaultHash, DefaultRng, IOPatternError};

/// A cryptographically-secure random number generator that is bound to the protocol transcript.
///
/// For most public-coin protocols it is *vital* not to have two commitments for the same challenge.
/// For most public-coin protocols it is *vital* not to have two different verifier messages for the same prover message.
/// For this reason, we construct a Rng that will absorb whatever the verifier absorbs, and that in addition
/// it is seeded by a cryptographic random number generator (by default, [`rand::rngs::OsRng`]).
///
Expand Down Expand Up @@ -50,7 +50,7 @@ impl<R: RngCore + CryptoRng> RngCore for ProverRng<R> {
}
}

impl<H, R, U> Arthur<H, R, U>
impl<H, U, R> Arthur<H, U, R>
where
H: DuplexHash<U>,
R: RngCore + CryptoRng,
Expand All @@ -71,7 +71,7 @@ where
}
}

impl<U, H, D> From<D> for Arthur<H, DefaultRng, U>
impl<U, H, D> From<D> for Arthur<H, U, DefaultRng>
where
U: Unit,
H: DuplexHash<U>,
Expand All @@ -84,11 +84,11 @@ where

/// The state of an interactive proof system.
/// Holds the state of the verifier, and provides the random coins for the prover.
pub struct Arthur<H = DefaultHash, R = DefaultRng, U = u8>
pub struct Arthur<H = DefaultHash, U = u8, R = DefaultRng>
where
U: Unit,
H: DuplexHash<U>,
R: RngCore + CryptoRng,
U: Unit,
{
/// The randomness state of the prover.
pub(crate) rng: ProverRng<R>,
Expand All @@ -98,7 +98,12 @@ where
pub(crate) transcript: Vec<u8>,
}

impl<R: RngCore + CryptoRng, U: Unit, H: DuplexHash<U>> Arthur<H, R, U> {
impl<H, U, R> Arthur<H, U, R>
where
U: Unit,
H: DuplexHash<U>,
R: RngCore + CryptoRng,
{
#[inline(always)]
pub fn add(&mut self, input: &[U]) -> Result<(), IOPatternError> {
// let serialized = bincode::serialize(input).unwrap();
Expand Down Expand Up @@ -129,7 +134,12 @@ impl<R: RngCore + CryptoRng, U: Unit, H: DuplexHash<U>> Arthur<H, R, U> {
}
}

impl<H: DuplexHash<U>, R: RngCore + CryptoRng, U: Unit> UnitTranscript<U> for Arthur<H, R, U> {
impl<H, U, R> UnitTranscript<U> for Arthur<H, U, R>
where
U: Unit,
H: DuplexHash<U>,
R: RngCore + CryptoRng,
{
fn public_units(&mut self, input: &[U]) -> Result<(), IOPatternError> {
let len = self.transcript.len();
self.add(input)?;
Expand All @@ -144,13 +154,22 @@ impl<H: DuplexHash<U>, R: RngCore + CryptoRng, U: Unit> UnitTranscript<U> for Ar

impl<R: RngCore + CryptoRng> CryptoRng for ProverRng<R> {}

impl<R: RngCore + CryptoRng, U: Unit, H: DuplexHash<U>> core::fmt::Debug for Arthur<H, R, U> {
impl<H, U, R> core::fmt::Debug for Arthur<H, U, R>
where
U: Unit,
H: DuplexHash<U>,
R: RngCore + CryptoRng,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.safe.fmt(f)
}
}

impl<H: DuplexHash, R: RngCore + CryptoRng> ByteWriter for Arthur<H, R> {
impl<H, R> ByteWriter for Arthur<H, u8, R>
where
H: DuplexHash<u8>,
R: RngCore + CryptoRng,
{
#[inline(always)]
fn add_bytes(&mut self, input: &[u8]) -> Result<(), IOPatternError> {
self.add(input)
Expand Down
2 changes: 1 addition & 1 deletion src/iopattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ impl<H: DuplexHash<U>, U: Unit> IOPattern<H, U> {
}
}

pub fn to_arthur(&self) -> crate::Arthur<H, crate::DefaultRng, U> {
pub fn to_arthur(&self) -> crate::Arthur<H, U, crate::DefaultRng> {
crate::Arthur::new(self, crate::DefaultRng::default())
}

Expand Down
8 changes: 4 additions & 4 deletions src/plugins/ark/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ where

// Field <-> Field interactions:

impl<H, R, C, const N: usize> FieldPublic<Fp<C, N>> for Arthur<H, R, Fp<C, N>>
impl<H, R, C, const N: usize> FieldPublic<Fp<C, N>> for Arthur<H, Fp<C, N>, R>
where
H: DuplexHash<Fp<C, N>>,
R: RngCore + CryptoRng,
Expand Down Expand Up @@ -139,7 +139,7 @@ where
}
}

impl<H, R, C, const N: usize, G> GroupPublic<G> for Arthur<H, R, Fp<C, N>>
impl<H, R, C, const N: usize, G> GroupPublic<G> for Arthur<H, Fp<C, N>, R>
where
C: FpConfig<N>,
R: RngCore + CryptoRng,
Expand Down Expand Up @@ -189,7 +189,7 @@ where
}
}

impl<'a, H, R, C, const N: usize> BytePublic for Arthur<H, R, Fp<C, N>>
impl<'a, H, R, C, const N: usize> BytePublic for Arthur<H, Fp<C, N>, R>
where
C: FpConfig<N>,
H: DuplexHash<Fp<C, N>>,
Expand All @@ -203,7 +203,7 @@ where
}
}

impl<'a, H, R, C, const N: usize> ByteChallenges for Arthur<H, R, Fp<C, N>>
impl<'a, H, R, C, const N: usize> ByteChallenges for Arthur<H, Fp<C, N>, R>
where
C: FpConfig<N>,
H: DuplexHash<Fp<C, N>>,
Expand Down
12 changes: 6 additions & 6 deletions src/plugins/ark/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rand::{CryptoRng, RngCore};
use super::{FieldPublic, FieldWriter, GroupPublic, GroupWriter};
use crate::{Arthur, DuplexHash, ProofResult, UnitTranscript};

impl<F: PrimeField, H: DuplexHash, R: RngCore + CryptoRng> FieldWriter<F> for Arthur<H, R> {
impl<F: PrimeField, H: DuplexHash, R: RngCore + CryptoRng> FieldWriter<F> for Arthur<H, u8, R> {
fn add_scalars(&mut self, input: &[F]) -> ProofResult<()> {
let serialized = self.public_scalars(input);
self.transcript.extend(serialized?);
Expand All @@ -15,7 +15,7 @@ impl<F: PrimeField, H: DuplexHash, R: RngCore + CryptoRng> FieldWriter<F> for Ar
}

impl<C: FpConfig<N>, H: DuplexHash<Fp<C, N>>, R: RngCore + CryptoRng, const N: usize>
FieldWriter<Fp<C, N>> for Arthur<H, R, Fp<C, N>>
FieldWriter<Fp<C, N>> for Arthur<H, Fp<C, N>, R>
{
fn add_scalars(&mut self, input: &[Fp<C, N>]) -> ProofResult<()> {
self.public_units(input)?;
Expand All @@ -26,13 +26,13 @@ impl<C: FpConfig<N>, H: DuplexHash<Fp<C, N>>, R: RngCore + CryptoRng, const N: u
}
}

impl<G, H, R> GroupWriter<G> for Arthur<H, R>
impl<G, H, R> GroupWriter<G> for Arthur<H, u8, R>
where
G: CurveGroup,
H: DuplexHash,
G::BaseField: PrimeField,
R: RngCore + CryptoRng,
Arthur<H, R>: GroupPublic<G, Repr = Vec<u8>>,
Arthur<H, u8, R>: GroupPublic<G, Repr = Vec<u8>>,
{
#[inline(always)]
fn add_points(&mut self, input: &[G]) -> ProofResult<()> {
Expand All @@ -43,12 +43,12 @@ where
}

impl<G, H, R, C: FpConfig<N>, C2: FpConfig<N>, const N: usize> GroupWriter<G>
for Arthur<H, R, Fp<C, N>>
for Arthur<H, Fp<C, N>, R>
where
G: CurveGroup<BaseField = Fp<C2, N>>,
H: DuplexHash<Fp<C, N>>,
R: RngCore + CryptoRng,
Arthur<H, R, Fp<C, N>>: GroupPublic<G> + FieldWriter<G::BaseField>,
Arthur<H, Fp<C, N>, R>: GroupPublic<G> + FieldWriter<G::BaseField>,
{
#[inline(always)]
fn add_points(&mut self, input: &[G]) -> ProofResult<()> {
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/group/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rand::{CryptoRng, RngCore};
use super::{FieldPublic, FieldWriter, GroupPublic, GroupWriter};
use crate::{Arthur, ByteWriter, DuplexHash, ProofResult};

impl<F, H, R> FieldWriter<F> for Arthur<H, R>
impl<F, H, R> FieldWriter<F> for Arthur<H, u8, R>
where
F: PrimeField,
H: DuplexHash,
Expand All @@ -17,7 +17,7 @@ where
}
}

impl<G, H, R, const N: usize> GroupPublic<G> for Arthur<H, R>
impl<G, H, R, const N: usize> GroupPublic<G> for Arthur<H, u8, R>
where
G: Group + GroupEncoding<Repr = [u8; N]>,
H: DuplexHash,
Expand All @@ -34,7 +34,7 @@ where
}
}

impl<G, H, R, const N: usize> GroupWriter<G> for Arthur<H, R>
impl<G, H, R, const N: usize> GroupWriter<G> for Arthur<H, u8, R>
where
G: Group + GroupEncoding<Repr = [u8; N]>,
H: DuplexHash,
Expand Down

0 comments on commit d726f04

Please sign in to comment.