Skip to content

Commit

Permalink
Minor cosmetics and consistency changes.
Browse files Browse the repository at this point in the history
Adds support for rust stable.
  • Loading branch information
mmaker committed Jul 29, 2023
1 parent d3cba93 commit 470a460
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 94 deletions.
142 changes: 94 additions & 48 deletions examples/bulletproofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,86 @@ use nimue::arkworks_plugins::{Absorbable, AlgebraicIO};
use nimue::IOPattern;
use nimue::{
arkworks_plugins::{Absorbs, FieldChallenges},
Duplexer, InvalidTag, Merlin,
Arthur, Duplexer, InvalidTag, Merlin,
};
use rand::rngs::OsRng;

fn fold_generators<G: AffineRepr>(
a: &[G],
b: &[G],
x: &G::ScalarField,
y: &G::ScalarField,
) -> Vec<G> {
a.iter()
.zip(b.iter())
.map(|(&a, &b)| (a * x + b * y).into_affine())
.collect()
}

/// Computes the inner prouct of vectors `a` and `b`.
///
/// Useless once https://github.com/arkworks-rs/algebra/pull/665 gets merged.
fn inner_prod<F: Field>(a: &[F], b: &[F]) -> F {
a.iter().zip(b.iter()).map(|(&a, &b)| a * b).sum()
}

/// Folds together `(a, b)` using challenges `x` and `y`.
fn fold<F: Field>(a: &[F], b: &[F], x: &F, y: &F) -> Vec<F> {
a.iter()
.zip(b.iter())
.map(|(&a, &b)| a * x + b * y)
.collect()
}

// The bulletproof proof.
struct Bulletproof<G: AffineRepr> {
proof: Vec<(G, G)>,
/// the prover's messages
round_msgs: Vec<(G, G)>,
/// the last round message
last: (G::ScalarField, G::ScalarField),
}

/// The IO Pattern of a bulleproof.
///
/// Defining this as a trait allows us to "attach" the bulletproof IO to
/// the base class [`nimue::IOPattern`] and have other protocol compose the IO pattern.
trait BulletproofIOPattern {
fn bulletproof_statement<G, S: Duplexer>(&self) -> Self
where
G: AffineRepr + Absorbable<S::L>;

fn bulletproof_io<G, S: Duplexer>(&self, len: usize) -> Self
where
G: AffineRepr + Absorbable<S::L>;
}

impl BulletproofIOPattern for IOPattern {
/// The IO of the bulletproof statement (the sole commitment)
fn bulletproof_statement<G, S: Duplexer>(&self) -> Self
where
G: AffineRepr + Absorbable<S::L>,
{
AlgebraicIO::<S>::from(self).absorb_point::<G>(1).into()
}

/// The IO of the bulletproof protocol
fn bulletproof_io<G, S>(&self, len: usize) -> Self
where
G: AffineRepr + Absorbable<S::L>,
S: Duplexer
S: Duplexer,
{
let mut pattern = AlgebraicIO::<S>::from(self).absorb_point::<G>(1);
let mut io_pattern = AlgebraicIO::<S>::from(self);
for _ in 0..log2(len) {
pattern = pattern.absorb_point::<G>(2).squeeze_bytes(16);
io_pattern = io_pattern.absorb_point::<G>(2).squeeze_bytes(16);
}
pattern.into()
io_pattern.into()
}
}

fn prove<S, G>(
transcript: &mut Merlin<S>,
transcript: &mut Arthur<S>,
generators: (&[G], &[G], &G),
statement: &G,
statement: &G, // the actual inner-roduct of the witness is not really needed
witness: (&[G::ScalarField], &[G::ScalarField]),
) -> Result<Bulletproof<G>, InvalidTag>
where
Expand All @@ -63,9 +110,8 @@ where
let c = a * b;
let left = g * a + h * b + u * c;
let right = *statement;
println!("{}", (left - right).is_zero());
return Ok(Bulletproof {
proof: vec![],
round_msgs: vec![],
last: (witness.0[0], witness.1[0]),
});
}
Expand Down Expand Up @@ -102,7 +148,10 @@ where
let new_statement = (*statement + left * x.square() + right * x_inv.square()).into_affine();

let mut bulletproof = prove(transcript, new_generators, &new_statement, new_witness)?;
bulletproof.proof.push((left_compressed, right_compressed));
// proof will be reverse-order
bulletproof
.round_msgs
.push((left_compressed, right_compressed));
Ok(bulletproof)
}

Expand All @@ -121,9 +170,9 @@ where
let u = *generators.2;
let mut statement = *statement;

let mut n = 1 << bulletproof.proof.len();
let mut n = 1 << bulletproof.round_msgs.len();
assert_eq!(g.len(), n);
for (left, right) in bulletproof.proof.iter().rev() {
for (left, right) in bulletproof.round_msgs.iter().rev() {
n /= 2;

let (g_left, g_right) = g.split_at(n);
Expand Down Expand Up @@ -154,55 +203,52 @@ fn main() {
use ark_std::UniformRand;

type H = nimue::DefaultHash;

let a = [1, 2, 3, 4, 5, 6, 7, 8].iter().map(|&x| F::from(x)).collect::<Vec<_>>();
let b = [1, 2, 3, 4, 5, 6, 7, 8].iter().map(|&x| F::from(x)).collect::<Vec<_>>();
// the vector size
let size = 8u64;

// initialize the IO Pattern putting the domain separator ("example.com")
let io_pattern = IOPattern::new("example.com")
// add the IO of the bulletproof statement (the commitment)
.bulletproof_statement::<G, H>()
// (optional) process the data so far, filling the block till the end.
.process()
// add the IO of the bulletproof protocol (the transcript)
.bulletproof_io::<G, H>(size as usize);

// the test vectors
let a = (0..size).map(|x| F::from(x)).collect::<Vec<_>>();
let b = (0..size).map(|x| F::from(x + 42)).collect::<Vec<_>>();
let ab = inner_prod(&a, &b);
// the generators to be used for respectively a, b, ip
let g = (0..a.len())
.map(|_| G::rand(&mut OsRng))
.collect::<Vec<_>>();
let h = (0..a.len())
.map(|_| G::rand(&mut OsRng))
.collect::<Vec<_>>();
let u = G::rand(&mut OsRng);
let ip = inner_prod(&a, &b);

let generators = (&g[..], &h[..], &u);
let statement =
(G1Projective::msm(&g, &a).unwrap() + G1Projective::msm(&h, &b).unwrap() + u * ip)
(G1Projective::msm(&g, &a).unwrap() + G1Projective::msm(&h, &b).unwrap() + u * ab)
.into_affine();
let witness = (&a[..], &b[..]);

let iop = IOPattern::new("example.com").bulletproof_io::<G, H>(a.len());
let mut transcript = Merlin::new(&iop);
transcript.append_element(&statement).unwrap();
let mut prover_transcript = Arthur::new(&io_pattern, OsRng);
prover_transcript.append_element(&statement).unwrap();
prover_transcript.process().unwrap();
let bulletproof =
prove::<nimue::keccak::Keccak, G>(&mut transcript, generators, &statement, witness)
prove::<nimue::keccak::Keccak, G>(&mut prover_transcript, generators, &statement, witness)
.unwrap();
let mut transcript = Merlin::<nimue::keccak::Keccak>::new(&iop);
transcript.append_element(&statement).unwrap();
verify(&mut transcript, generators, &statement, &bulletproof).expect("Invalid proof");
}

fn fold<F: Field>(a: &[F], b: &[F], x: &F, y: &F) -> Vec<F> {
a.iter()
.zip(b.iter())
.map(|(&a, &b)| a * x + b * y)
.collect()
}

fn fold_generators<G: AffineRepr>(
a: &[G],
b: &[G],
x: &G::ScalarField,
y: &G::ScalarField,
) -> Vec<G> {
a.iter()
.zip(b.iter())
.map(|(&a, &b)| (a * x + b * y).into_affine())
.collect()
}


fn inner_prod<F: Field>(a: &[F], b: &[F]) -> F {
a.iter().zip(b.iter()).map(|(&a, &b)| a * b).sum()
let mut verifier_transcript = Merlin::<nimue::keccak::Keccak>::new(&io_pattern);
verifier_transcript.append_element(&statement).unwrap();
verifier_transcript.process().unwrap();
verify(
&mut verifier_transcript,
generators,
&statement,
&bulletproof,
)
.expect("Invalid proof");
}
34 changes: 26 additions & 8 deletions examples/schnorr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,36 @@ use ark_ec::{AffineRepr, CurveGroup};
use ark_serialize::CanonicalSerialize;
use ark_std::UniformRand;
use nimue::arkworks_plugins::{Absorbable, Absorbs, AlgebraicIO, FieldChallenges};
use nimue::{Duplexer, IOPattern, InvalidTag, Merlin, Arthur};
use nimue::{Arthur, Duplexer, IOPattern, InvalidTag, Merlin};

trait SchnorrIOPattern {
fn schnorr_statement<G, S: Duplexer>(&self) -> Self
where
G: AffineRepr + Absorbable<S::L>;

fn schnorr_io<G, S: Duplexer>(&self) -> Self
where
G: AffineRepr + Absorbable<S::L>;
}

impl SchnorrIOPattern for IOPattern {
/// A Schnorr signature's IO Pattern.
fn schnorr_io<G, S: Duplexer>(&self) -> IOPattern
fn schnorr_statement<G, S: Duplexer>(&self) -> Self
where
G: AffineRepr + Absorbable<S::L>,
{
// the statement: generator and public key
AlgebraicIO::<S>::from(self)
// the statement: generator and public key
.absorb_point::<G>(2)
// (optional) allow for preprocessing of the generators
.process()
.into()
}

/// A Schnorr signature's IO Pattern.
fn schnorr_io<G, S: Duplexer>(&self) -> IOPattern
where
G: AffineRepr + Absorbable<S::L>,
{
AlgebraicIO::<S>::from(self)
// absorb the commitment
.absorb_point::<G>(1)
// challenge in bytes
Expand All @@ -29,7 +40,7 @@ impl SchnorrIOPattern for IOPattern {
}
}

fn schnorr_proof<S: Duplexer, G: AffineRepr + Absorbable<S::L>>(
fn prove<S: Duplexer, G: AffineRepr + Absorbable<S::L>>(
transcript: &mut Arthur<S>,
sk: G::ScalarField,
g: G,
Expand Down Expand Up @@ -80,14 +91,21 @@ fn main() {
type G = ark_bls12_381::G1Affine;
type F = ark_bls12_381::Fr;

let io_pattern = IOPattern::new("domsep").schnorr_io::<G, H>();
let io_pattern = IOPattern::new("the domain separator goes here")
// append the statement (generator, public key)
.schnorr_statement::<G, H>()
// process the statement separating it from the rest of the protocol
.process()
// add the schnorr io pattern
.schnorr_io::<G, H>();
let sk = F::rand(&mut OsRng);
let g = G::generator();
let mut writer = Vec::new();
g.serialize_compressed(&mut writer).unwrap();
let pk = (g * &sk).into();

let mut prover_transcript = Arthur::<H>::from(io_pattern.clone());
let proof = schnorr_proof::<H, G>(&mut prover_transcript, sk, g, pk).expect("Valid proof");
let proof = prove::<H, G>(&mut prover_transcript, sk, g, pk).expect("Valid proof");

let mut verifier_transcript = Merlin::from(io_pattern.clone());
verify::<H, G>(&mut verifier_transcript, g, pk, proof).expect("Valid proof");
Expand Down
2 changes: 1 addition & 1 deletion src/arkworks_plugins/absorbs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{Lane, Merlin};

use super::super::{Duplexer, InvalidTag, Arthur};
use super::super::{Arthur, Duplexer, InvalidTag};
use super::Absorbable;
use rand::{CryptoRng, RngCore};

Expand Down
4 changes: 1 addition & 3 deletions src/arkworks_plugins/field_challenges.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use super::super::{Duplexer, InvalidTag, Merlin, Arthur};
use super::super::{Arthur, Duplexer, InvalidTag, Merlin};
use ark_ff::PrimeField;
use rand::{CryptoRng, RngCore};



pub trait FieldChallenges {
/// Squeeze a field element challenge of `byte_count` bytes
/// from the protocol transcript.
Expand Down
9 changes: 5 additions & 4 deletions src/arkworks_plugins/iopattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ark_ff::{Field, PrimeField};
use core::borrow::Borrow;

use super::{
super::{Duplexer, IOPattern, Lane, Merlin, Arthur},
super::{Arthur, Duplexer, IOPattern, Lane, Merlin},
Absorbable,
};

Expand Down Expand Up @@ -40,7 +40,7 @@ where
}

pub fn absorb_bytes(self, count: usize) -> Self {
let count = usize::div_ceil(count, S::L::compressed_size());
let count = crate::div_ceil!(count, S::L::compressed_size());
self.iop.absorb(count).into()
}

Expand All @@ -60,13 +60,14 @@ where
}

pub fn squeeze_bytes(self, count: usize) -> Self {
let count = usize::div_ceil(count, S::L::extractable_bytelen());
let count = crate::div_ceil!(count, S::L::extractable_bytelen());
self.iop.squeeze(count).into()
}

pub fn squeeze_field<F: PrimeField>(self, count: usize) -> Self {
// XXX. check if typeof::<F>() == typeof::<S::L>() and if so use native squeeze
self.squeeze_bytes(super::random_felt_bytelen::<F>() * count).into()
self.squeeze_bytes(super::random_felt_bytelen::<F>() * count)
.into()
}
}

Expand Down
16 changes: 7 additions & 9 deletions src/arkworks_plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod iopattern;
pub use absorbs::Absorbs;

use ark_ec::{
short_weierstrass::{Affine, SWCurveConfig, Projective},
short_weierstrass::{Affine, Projective, SWCurveConfig},
AffineRepr, CurveGroup,
};
use ark_ff::{BigInteger, Fp, FpConfig, PrimeField};
Expand Down Expand Up @@ -62,10 +62,12 @@ impl<const N: usize, C: FpConfig<N>, P: SWCurveConfig<BaseField = Fp<C, N>>> Abs
}

// this one little `where` trick avoids specifying in any implementation `Projective<P>: Absorbable<L>`.
impl<'a, P: SWCurveConfig, L: Lane> Absorbable<L> for Affine<P> where
Projective<P>: Absorbable<L> {
impl<'a, P: SWCurveConfig, L: Lane> Absorbable<L> for Affine<P>
where
Projective<P>: Absorbable<L>,
{
fn absorb_size() -> usize {
usize::div_ceil(Self::default().compressed_size(), L::compressed_size())
crate::div_ceil!(Self::default().compressed_size(), L::compressed_size())
}

fn to_absorbable(&self) -> Vec<L> {
Expand All @@ -75,20 +77,16 @@ impl<'a, P: SWCurveConfig, L: Lane> Absorbable<L> for Affine<P> where
}
}

impl<P: SWCurveConfig, L: Lane> Absorbable<L> for Projective<P> {
impl<P: SWCurveConfig, L: Lane> Absorbable<L> for Projective<P> {
fn absorb_size() -> usize {
<Affine<P> as Absorbable<L>>::absorb_size()
}

fn to_absorbable(&self) -> Vec<L> {
<Affine<P> as Absorbable<L>>::to_absorbable(&self.into_affine())

}
}




#[macro_export]
macro_rules! impl_absorbable {
($t:ty) => {
Expand Down
Loading

0 comments on commit 470a460

Please sign in to comment.