Skip to content

Commit

Permalink
Examples working again, added Poseidon hash.
Browse files Browse the repository at this point in the history
  • Loading branch information
mmaker committed Jan 29, 2024
1 parent 16b776d commit 8ada768
Show file tree
Hide file tree
Showing 12 changed files with 324 additions and 260 deletions.
14 changes: 6 additions & 8 deletions examples/bulletproof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ where
{
assert_eq!(witness.0.len(), witness.1.len());

arthur.public_points(&[*statement]).unwrap();
arthur.ratchet().unwrap();

if witness.0.len() == 1 {
assert_eq!(generators.0.len(), 1);

Expand Down Expand Up @@ -99,9 +96,6 @@ fn verify<G: CurveGroup>(
where
for<'a> Merlin<'a>: GroupReader<G> + FieldChallenges<G::ScalarField>,
{
merlin.public_points(&[*statement]).unwrap();
merlin.ratchet().unwrap();

let mut g = generators.0.to_vec();
let mut h = generators.1.to_vec();
let u = generators.2.clone();
Expand Down Expand Up @@ -196,13 +190,17 @@ fn main() {
let witness = (&a[..], &b[..]);

let mut arthur = iopattern.to_arthur();
arthur.public_points(&[statement]).unwrap();
arthur.ratchet().unwrap();
let proof = prove(&mut arthur, generators, &statement, witness).expect("Error proving");
println!(
"Here's a bulletproof for {} elements:\n{}",
size,
hex::encode(proof)
);

let mut verifier_transcript = iopattern.to_merlin(proof);
verify(&mut verifier_transcript, generators, size, &statement).expect("Invalid proof");
let mut merlin = iopattern.to_merlin(proof);
merlin.public_points(&[statement]).unwrap();
merlin.ratchet().unwrap();
verify(&mut merlin, generators, size, &statement).expect("Invalid proof");
}
19 changes: 9 additions & 10 deletions examples/schnorr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ where
G: CurveGroup,
Arthur<H>: GroupWriter<G> + FieldChallenges<G::ScalarField>,
{
arthur.public_points(&[P, P * x]).unwrap();
arthur.ratchet().unwrap();

// `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.
let k = G::ScalarField::rand(arthur.rng());
Expand Down Expand Up @@ -114,12 +111,12 @@ fn verify<G, H>(
where
G: CurveGroup,
H: DuplexHash,
for<'a> Merlin<'a, H>: GroupReader<G> + FieldChallenges<G::ScalarField>,
for<'a> Merlin<'a, H>:
GroupReader<G> + FieldReader<G::ScalarField> + FieldChallenges<G::ScalarField>,
{
merlin.public_points(&[P, X]).unwrap();
merlin.ratchet().unwrap();

// Read the protocol from the transcript:
// XXX. possible inconsistent implementations:
// if the point is not validated here (but the public key is) then the proof may fail with InvalidProof, instead of SerializationError
let [K] = merlin.next_points().unwrap();
let [c] = merlin.challenge_scalars().unwrap();
let [r] = merlin.next_scalars().unwrap();
Expand All @@ -146,19 +143,21 @@ fn main() {
type G = ark_curve25519::EdwardsProjective;
// Set the hash function (commented out other valid choices):
// type H = nimue::hash::Keccak;
// type H = nimue::hash::legacy::DigestBridge<blake2::Blake2s256>;
type H = nimue::hash::legacy::DigestBridge<blake2::Blake2s256>;
// type H = nimue::hash::legacy::DigestBridge<sha2::Sha256>;

// Set up the IO for the protocol transcript with domain separator "nimue::examples::schnorr"
let io = IOPattern::new("nimue::examples::schnorr");
let io = IOPattern::<H>::new("nimue::examples::schnorr");
let io = SchnorrIOPattern::<G>::add_schnorr_io(io);

// Set up the elements to prove
let P = G::generator();
let (x, X) = keygen();

// Create the prover transcript, add the statement to it, and then invoke the prover.
let mut arthur: Arthur = io.to_arthur();
let mut arthur = io.to_arthur();
arthur.public_points(&[P, P * x]).unwrap();
arthur.ratchet().unwrap();
let proof = prove(&mut arthur, P, x).expect("Invalid proof");

// Print out the hex-encoded schnorr proof.
Expand Down
45 changes: 26 additions & 19 deletions examples/schnorr_algebraic_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,22 @@ 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 aprove<G, H, R>(
fn prove<G, H, U, R>(
// 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, G::BaseField>,
arthur: &mut Arthur<H, R, U>,
// the generator
P: G,
// the secret key
x: G::ScalarField,
) -> ProofResult<&[u8]>
where
G::BaseField: Unit,
U: Unit,
G::BaseField: PrimeField,
R: CryptoRng + RngCore,
H: DuplexHash<G::BaseField>,
H: DuplexHash<U>,
G: CurveGroup,
Arthur<H, R, G::BaseField>: GroupWriter<G> + ByteChallenges,
Arthur<H, R, 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 All @@ -74,9 +75,10 @@ where
let c_bytes = arthur.challenge_bytes::<16>()?;
let c = G::ScalarField::from_le_bytes_mod_order(&c_bytes);

let _r = k + c * x;
let r = k + c * x;
let r_q = swap_field::<G::ScalarField, G::BaseField>(r)?;
// Add a sequence of scalar elements to the protocol transcript.
// arthur.add_scalars(&[r])?;
arthur.add_scalars(&[r_q])?;

// Output the current protocol transcript as a sequence of bytes.
Ok(arthur.transcript())
Expand All @@ -87,27 +89,28 @@ where
/// - the secret key `witness`
/// It returns a zero-knowledge proof of knowledge of `witness` as a sequence of bytes.
#[allow(non_snake_case)]
fn averify<'a, G, H>(
fn verify<'a, G, H, U>(
// `ArkGroupMelin` contains the veirifier state, including the messages currently read. In addition, it is aware of the group `G`
// from which it can serialize/deserialize elements.
merlin: &mut Merlin<'a, H, G::BaseField>,
merlin: &mut Merlin<'a, H, U>,
// The group generator `P``
P: G,
// The public key `X`
X: G,
) -> ProofResult<()>
where
G::BaseField: Unit,
U: Unit,
G::BaseField: PrimeField,
G: CurveGroup,
H: DuplexHash<G::BaseField>,
Merlin<'a, H, G::BaseField>: GroupReader<G> + ByteChallenges,
H: DuplexHash<U>,
Merlin<'a, H, U>: GroupReader<G> + FieldReader<G::BaseField> + ByteChallenges,
{
// Read the protocol from the transcript:
let [K] = merlin.next_points().unwrap();
let c_bytes = merlin.challenge_bytes::<16>().unwrap();
let c = G::ScalarField::from_le_bytes_mod_order(&c_bytes);
let r = G::ScalarField::from(0);
// let [r] = merlin.next_scalars().unwrap();
let [r_q] = merlin.next_scalars().unwrap();
let r = swap_field::<G::BaseField, G::ScalarField>(r_q)?;

// Check the verification equation, otherwise return a verification error.
// The type ProofError is an enum that can report:
Expand Down Expand Up @@ -136,26 +139,30 @@ fn main() {
// type H = nimue::hash::legacy::DigestBridge<sha2::Sha256>;
type H = nimue::plugins::ark::poseidon::PoseidonHash;

//
// type U = u8;
type U = Fq;

// Set up the IO for the protocol transcript with domain separator "nimue::examples::schnorr"
let io = IOPattern::<H, Fq>::new("nimue::examples::schnorr");
let io = IOPattern::<H, U>::new("nimue::examples::schnorr");
let io = SchnorrIOPattern::<G>::add_schnorr_io(io);

// Set up the elements to prove
let P = G::generator();
let (x, X) = keygen();

// Create the prover transcript, add the statement to it, and then invoke the prover.
let mut arthur: Arthur<H, OsRng, Fq> = Arthur::<H, _, Fq>::new(&io, OsRng);
let mut arthur = Arthur::<H, _, U>::new(&io, OsRng);
arthur.public_points(&[P, X]).unwrap();
arthur.ratchet().unwrap();
let proof = aprove(&mut arthur, P, x).expect("Invalid proof");
let proof = prove(&mut arthur, P, x).expect("Invalid proof");

// Print out the hex-encoded schnorr proof.
println!("Here's a Schnorr signature:\n{}", hex::encode(proof));

// Verify the proof: create the verifier transcript, add the statement to it, and invoke the verifier.
let mut merlin = Merlin::<H, Fq>::new(&io, &proof);
let mut merlin = Merlin::<H, U>::new(&io, &proof);
merlin.public_points(&[P, X]).unwrap();
merlin.ratchet().unwrap();
averify(&mut merlin, P, X).expect("Invalid proof");
verify(&mut merlin, P, X).expect("Invalid proof");
}
6 changes: 6 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,9 @@ impl<B: Borrow<IOPatternError>> From<B> for ProofError {
ProofError::InvalidIO(value.borrow().clone())
}
}

impl From<std::io::Error> for IOPatternError {
fn from(value: std::io::Error) -> Self {
IOPatternError(value.to_string())
}
}
5 changes: 3 additions & 2 deletions src/merlin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ impl<'a, U: Unit, H: DuplexHash<U>> Merlin<'a, H, U> {
/// Read `input.len()` elements from the transcript.
#[inline(always)]
pub fn fill_next(&mut self, input: &mut [U]) -> Result<(), IOPatternError> {
U::read(&mut self.transcript, input).unwrap();
self.safe.absorb(input)
U::read(&mut self.transcript, input)?;
self.safe.absorb(input)?;
Ok(())
}

/// Signals the end of the statement.
Expand Down
13 changes: 7 additions & 6 deletions src/plugins/ark/common.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::io;

use ark_ec::{AffineRepr, CurveGroup};
use ark_ff::{Fp, FpConfig, PrimeField};
use ark_ff::{Field, Fp, FpConfig, PrimeField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError};
use rand::{CryptoRng, RngCore};

Expand All @@ -25,8 +25,10 @@ impl<C: FpConfig<N>, const N: usize> Unit for Fp<C, N> {

fn read(mut r: &mut impl io::Read, bunch: &mut [Self]) -> Result<(), io::Error> {
for b in bunch.iter_mut() {
*b = ark_ff::Fp::<C, N>::deserialize_compressed(&mut r)
.map_err(|_| io::Error::new(io::ErrorKind::Other, "oh no!"))?
let b_result = Fp::deserialize_compressed(&mut r);
*b = b_result.map_err(|_| {
io::Error::new(io::ErrorKind::Other, "Unable to deserialize into Field.")
})?
}
Ok(())
}
Expand Down Expand Up @@ -58,7 +60,7 @@ where

impl<T, F> FieldPublic<F> for T
where
F: PrimeField,
F: Field,
T: UnitTranscript<u8>,
{
type Repr = Vec<u8>;
Expand All @@ -83,7 +85,7 @@ where

for o in output.iter_mut() {
self.fill_challenge_bytes(&mut buf)?;
*o = F::from_be_bytes_mod_order(&buf);
*o = F::from_be_bytes_mod_order(&buf).into();
}
Ok(())
}
Expand Down Expand Up @@ -172,7 +174,6 @@ where
}
}


// Field <-> Bytes interactions:

impl<'a, H, C, const N: usize> BytePublic for Merlin<'a, H, Fp<C, N>>
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/ark/iopattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ where

fn challenge_bytes(self, count: usize, label: &str) -> Self {
let n = bytes_uniform_modp(Fp::<C, N>::MODULUS_BIT_SIZE);
self.absorb((count + n - 1) / n, label)
self.squeeze((count + n - 1) / n, label)
}
}

Expand All @@ -62,7 +62,7 @@ where
G: CurveGroup<BaseField = Fp<C, N>>,
H: DuplexHash<Fp<C, N>>,
C: FpConfig<N>,
IOPattern<H, ark_ff::Fp<C, N>>: FieldIOPattern<G::BaseField>,
IOPattern<H, Fp<C, N>>: FieldIOPattern<Fp<C, N>>,
{
fn add_points(self, count: usize, label: &str) -> Self {
self.absorb(count * 2, label)
Expand Down
16 changes: 14 additions & 2 deletions src/plugins/ark/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,20 @@ pub mod poseidon;
pub use crate::traits::*;
pub use crate::{hash::Unit, Arthur, DuplexHash, IOPattern, Merlin, ProofError, ProofResult, Safe};

super::traits::field_traits!(ark_ff::PrimeField);
super::traits::group_traits!(ark_ec::CurveGroup, G::Scalar : ark_ff::Field);
super::traits::field_traits!(ark_ff::Field);
super::traits::group_traits!(ark_ec::CurveGroup, G::BaseField : ark_ff::PrimeField);

/// Move a value from one field to another.
///
/// Return an error if the value is larger than the destination field.
pub fn swap_field<F1: ark_ff::PrimeField, F2: ark_ff::PrimeField>(a_f1: F1) -> ProofResult<F2> {
use ark_ff::BigInteger;
let a_f2 = F2::from_le_bytes_mod_order(&a_f1.into_bigint().to_bytes_le());
let a_f1_control = F1::from_le_bytes_mod_order(&a_f2.into_bigint().to_bytes_le());
(a_f1 == a_f1_control)
.then(|| a_f2)
.ok_or(ProofError::SerializationError)
}

// pub trait PairingReader<P: ark_ec::pairing::Pairing>: GroupReader<P::G1> + GroupReader<P::G2> {
// fn fill_next_g1_points(&mut self, input: &mut [P::G1]) -> crate::ProofResult<()> {
Expand Down
Loading

0 comments on commit 8ada768

Please sign in to comment.