From b9c684b97cb6783dd394e694b80aca9a6de9819d Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Sun, 22 Dec 2024 16:53:57 +0100
Subject: [PATCH 1/9] exploratory work
---
Cargo.toml | 24 +++-
examples/less_than.rs | 175 ++++++++++++++++------------
src/bellpepper/mod.rs | 79 ++++++-------
src/bellpepper/r1cs.rs | 106 ++---------------
src/bellpepper/shape_cs.rs | 4 +-
src/bellpepper/solver.rs | 5 +-
src/bellpepper/test_shape_cs.rs | 4 +-
src/digest.rs | 13 +--
src/lib.rs | 127 ++++++++++++---------
src/provider/ark.rs | 190 +++++++++++++++++++++++++++++++
src/provider/ark_serde.rs | 36 ++++++
src/provider/bn256_grumpkin.rs | 28 ++---
src/provider/ipa_pc.rs | 10 +-
src/provider/keccak.rs | 60 ++++++----
src/provider/mod.rs | 108 ++++++------------
src/provider/pasta.rs | 8 ++
src/provider/pedersen.rs | 8 ++
src/provider/secp_secq.rs | 49 +++-----
src/r1cs.rs | 49 +++++++-
src/spartan/mod.rs | 2 +-
src/spartan/polys/eq.rs | 12 +-
src/spartan/polys/multilinear.rs | 34 +++---
src/spartan/polys/univariate.rs | 41 +++----
src/spartan/ppsnark.rs | 104 +++++++++++++----
src/spartan/snark.rs | 91 ++++++++++-----
src/spartan/sumcheck.rs | 3 +-
src/traits/mod.rs | 46 ++++----
src/traits/snark.rs | 10 +-
28 files changed, 876 insertions(+), 550 deletions(-)
create mode 100644 src/provider/ark.rs
create mode 100644 src/provider/ark_serde.rs
diff --git a/Cargo.toml b/Cargo.toml
index 8aa97b6..850b415 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,8 +11,6 @@ license-file = "LICENSE"
keywords = ["zkSNARKs", "cryptography", "proofs"]
[dependencies]
-bellpepper-core = "0.2.1"
-ff = { version = "0.13.0", features = ["derive"] }
digest = "0.10"
sha3 = "0.10"
rayon = "1.7"
@@ -27,13 +25,27 @@ num-traits = "0.2"
num-integer = "0.1"
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3"
-flate2 = "1.0"
bitvec = "1.0"
byteorder = "1.4.3"
thiserror = "1.0"
halo2curves = { version = "0.4.0", features = ["derive_serde"] }
group = "0.13.0"
once_cell = "1.18.0"
+derive_more = { version = "^1.0.0", features = ["full"] }
+
+# Arkworks
+ark-ec = { version = "^0.5.0", default-features = false }
+ark-ff = { version = "^0.5.0", default-features = false }
+ark-std = { version = "^0.5.0", default-features = false }
+ark-serialize = { version = "^0.5.0", default-features = false, features = ["derive"] }
+ark-snark = { version = "^0.5.1", default-features = false }
+ark-bls12-381 = { version = "^0.5.0", default-features = false, features = ["curve"] }
+ark-relations = { version = "^0.5.1", default-features = false }
+zeroize = { version = "^1.8.1", default-features = false }
+delegate = "0.13.1"
+serde_with = "3.12.0"
+sha2 = "0.10.7"
+ark-r1cs-std = "0.5.0"
[target.'cfg(any(target_arch = "x86_64", target_arch = "aarch64"))'.dependencies]
pasta-msm = { version = "0.1.4" }
@@ -52,7 +64,11 @@ sha2 = "0.10.7"
proptest = "1.2.0"
[features]
-default = []
+default = [
+ "ark-ec/parallel",
+ "ark-ff/parallel",
+ "ark-std/parallel",
+]
# Compiles in portable mode, w/o ISA extensions => binary can be executed on all systems.
portable = ["pasta-msm/portable"]
flamegraph = ["pprof/flamegraph", "pprof/criterion"]
diff --git a/examples/less_than.rs b/examples/less_than.rs
index a3bac59..bca5392 100644
--- a/examples/less_than.rs
+++ b/examples/less_than.rs
@@ -1,57 +1,67 @@
-use bellpepper_core::{
- boolean::AllocatedBit, num::AllocatedNum, Circuit, ConstraintSystem, LinearCombination,
- SynthesisError,
+use ark_bls12_381::Fr;
+use ark_ff::{BigInteger, PrimeField};
+use ark_r1cs_std::alloc::AllocVar;
+use ark_r1cs_std::boolean::AllocatedBool;
+use ark_r1cs_std::fields::fp::AllocatedFp;
+use ark_relations::r1cs::{
+ ConstraintSynthesizer, ConstraintSystemRef, LinearCombination, Namespace, SynthesisError,
+ Variable,
};
-use ff::{PrimeField, PrimeFieldBits};
-use pasta_curves::Fq;
+use num_traits::One;
use spartan2::{
errors::SpartanError,
traits::{snark::RelaxedR1CSSNARKTrait, Group},
SNARK,
};
-fn num_to_bits_le_bounded>(
- cs: &mut CS,
- n: AllocatedNum,
+fn num_to_bits_le_bounded(
+ cs: ConstraintSystemRef,
+ n: AllocatedFp,
num_bits: u8,
-) -> Result, SynthesisError> {
- let opt_bits = match n.get_value() {
- Some(v) => v
- .to_le_bits()
- .into_iter()
- .take(num_bits as usize)
- .map(Some)
- .collect::>>(),
- None => vec![None; num_bits as usize],
- };
+) -> Result>, SynthesisError> {
+ let opt_bits = n
+ .value()?
+ .into_bigint()
+ .to_bits_le()
+ .into_iter()
+ .take(num_bits as usize)
+ .map(Some)
+ .collect::>>();
// Add one witness per input bit in little-endian bit order
let bits_circuit = opt_bits.into_iter()
.enumerate()
- // AllocateBit enforces the value to be 0 or 1 at the constraint level
- .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("b_{}", i)), b).unwrap())
- .collect::>();
+ // Boolean enforces the value to be 0 or 1 at the constraint level
+ .map(|(i, b)| {
+ // TODO: Why do I need namespaces here?
+ let namespaced_cs = Namespace::from(cs.clone());
+ // TODO: Is it a "new_input" or a different type of a variable?
+ AllocatedBool::::new_input(namespaced_cs, || b.ok_or(SynthesisError::AssignmentMissing))
+ })
+ .collect::>, SynthesisError>>()?;
let mut weighted_sum_lc = LinearCombination::zero();
let mut pow2 = F::ONE;
for bit in bits_circuit.iter() {
- weighted_sum_lc = weighted_sum_lc + (pow2, bit.get_variable());
+ weighted_sum_lc = weighted_sum_lc + (pow2, bit.variable());
pow2 = pow2.double();
}
- cs.enforce(
- || "bit decomposition check",
- |lc| lc + &weighted_sum_lc,
- |lc| lc + CS::one(),
- |lc| lc + n.get_variable(),
- );
+ // weighted_sum_lc == n
+ let constraint_lc = weighted_sum_lc - n.variable;
+
+ // Enforce constraint_lc == 0
+ let one_lc = LinearCombination::from((One::one(), Variable::One));
+ cs.enforce_constraint(constraint_lc, one_lc, LinearCombination::zero())
+ .expect("Failed to enforce the linear combination constraint");
Ok(bits_circuit)
}
-fn get_msb_index(n: F) -> u8 {
- n.to_le_bits()
+fn get_msb_index(n: F) -> u8 {
+ n.into_bigint()
+ .to_bits_le()
.into_iter()
.enumerate()
.rev()
@@ -69,12 +79,12 @@ fn get_msb_index(n: F) -> u8 {
// a safe version.
#[derive(Clone, Debug)]
struct LessThanCircuitUnsafe {
- bound: F, // Will be a constant in the constraits, not a variable
+ bound: F, // Will be a constant in the constraints, not a variable
input: F, // Will be an input/output variable
num_bits: u8,
}
-impl LessThanCircuitUnsafe {
+impl LessThanCircuitUnsafe {
fn new(bound: F, input: F, num_bits: u8) -> Self {
assert!(get_msb_index(bound) < num_bits);
Self {
@@ -85,32 +95,46 @@ impl LessThanCircuitUnsafe {
}
}
-impl Circuit for LessThanCircuitUnsafe {
- fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> {
- assert!(F::NUM_BITS > self.num_bits as u32 + 1);
+impl ConstraintSynthesizer for LessThanCircuitUnsafe {
+ fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> {
+ assert!(F::MODULUS_BIT_SIZE > self.num_bits as u32 + 1);
- let input = AllocatedNum::alloc(cs.namespace(|| "input"), || Ok(self.input))?;
+ // TODO: It is possible to create Namespace with an numerical id, tracing::Id.
+ // Would that be useful?
+ // TODO: Use ns!() macro instead
+ let input_ns = Namespace::from(cs.clone());
+ let input = AllocatedFp::::new_input(input_ns, || Ok(self.input))?;
- let shifted_diff = AllocatedNum::alloc(cs.namespace(|| "shifted_diff"), || {
+ let shifted_ns = Namespace::from(cs.clone());
+ // TODO: Is this an input or a variable?
+ let shifted_diff = AllocatedFp::::new_input(shifted_ns, || {
Ok(self.input + F::from(1 << self.num_bits) - self.bound)
})?;
- cs.enforce(
- || "shifted_diff_computation",
- |lc| lc + input.get_variable() + (F::from(1 << self.num_bits) - self.bound, CS::one()),
- |lc: LinearCombination| lc + CS::one(),
- |lc| lc + shifted_diff.get_variable(),
- );
+ let shifted_diff_lc = LinearCombination::from(input.variable)
+ + LinearCombination::from((F::from(1 << self.num_bits) - self.bound, Variable::One))
+ - shifted_diff.variable;
+
+ // Enforce the linear combination (shifted_diff_lc == 0)
+ cs.enforce_constraint(
+ shifted_diff_lc,
+ LinearCombination::from((F::ONE, Variable::One)),
+ LinearCombination::zero(),
+ )?;
+
+ let shifted_diff_bits =
+ num_to_bits_le_bounded::(cs.clone(), shifted_diff, self.num_bits + 1)?;
- let shifted_diff_bits = num_to_bits_le_bounded::(cs, shifted_diff, self.num_bits + 1)?;
+ // Check that the last (i.e. most significant) bit is 0
+ let msb_var = shifted_diff_bits[self.num_bits as usize].variable();
+ let zero_lc = LinearCombination::zero();
- // Check that the last (i.e. most sifnificant) bit is 0
- cs.enforce(
- || "bound_check",
- |lc| lc + shifted_diff_bits[self.num_bits as usize].get_variable(),
- |lc| lc + CS::one(),
- |lc| lc + (F::ZERO, CS::one()),
- );
+ // Enforce the constraint that the most significant bit is 0
+ cs.enforce_constraint(
+ LinearCombination::from((F::ONE, msb_var)),
+ LinearCombination::from((F::ONE, Variable::One)),
+ zero_lc,
+ )?;
Ok(())
}
@@ -122,13 +146,13 @@ impl Circuit for LessThanCircuitUnsafe {
// Furthermore, the input must fit into `num_bits`, which is enforced at the
// constraint level.
#[derive(Clone, Debug)]
-struct LessThanCircuitSafe {
+struct LessThanCircuitSafe {
bound: F,
input: F,
num_bits: u8,
}
-impl LessThanCircuitSafe {
+impl LessThanCircuitSafe {
fn new(bound: F, input: F, num_bits: u8) -> Self {
assert!(get_msb_index(bound) < num_bits);
Self {
@@ -139,23 +163,26 @@ impl LessThanCircuitSafe {
}
}
-impl Circuit for LessThanCircuitSafe {
- fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> {
- let input = AllocatedNum::alloc(cs.namespace(|| "input"), || Ok(self.input))?;
+impl ConstraintSynthesizer for LessThanCircuitSafe {
+ fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> {
+ // TODO: Do we need to use a namespace here?
+ let input_ns = Namespace::from(cs.clone());
+ let input = AllocatedFp::::new_input(input_ns, || Ok(self.input))?;
// Perform the input bit decomposition check
- num_to_bits_le_bounded::(cs, input, self.num_bits)?;
+ num_to_bits_le_bounded::(cs.clone(), input, self.num_bits)?;
+ // TODO: Not sure how/why to do this in Arkworks
// Entering a new namespace to prefix variables in the
// LessThanCircuitUnsafe, thus avoiding name clashes
- cs.push_namespace(|| "less_than_safe");
+ // cs.push_namespace(|| "less_than_safe");
LessThanCircuitUnsafe {
bound: self.bound,
input: self.input,
num_bits: self.num_bits,
}
- .synthesize(cs)
+ .generate_constraints(cs)
}
}
@@ -194,43 +221,43 @@ fn verify_circuit_safe>(
}
fn main() {
- type G = pasta_curves::pallas::Point;
+ type G = ark_bls12_381::G1Projective;
type EE = spartan2::provider::ipa_pc::EvaluationEngine;
type S = spartan2::spartan::snark::RelaxedR1CSSNARK;
println!("Executing unsafe circuit...");
//Typical example, ok
- assert!(verify_circuit_unsafe::(Fq::from(17), Fq::from(9), 10).is_ok());
+ assert!(verify_circuit_unsafe::(Fr::from(17), Fr::from(9), 10).is_ok());
// Typical example, err
- assert!(verify_circuit_unsafe::(Fq::from(17), Fq::from(20), 10).is_err());
+ assert!(verify_circuit_unsafe::(Fr::from(17), Fr::from(20), 10).is_err());
// Edge case, err
- assert!(verify_circuit_unsafe::(Fq::from(4), Fq::from(4), 10).is_err());
+ assert!(verify_circuit_unsafe::(Fr::from(4), Fr::from(4), 10).is_err());
// Edge case, ok
- assert!(verify_circuit_unsafe::(Fq::from(4), Fq::from(3), 10).is_ok());
+ assert!(verify_circuit_unsafe::(Fr::from(4), Fr::from(3), 10).is_ok());
// Minimum number of bits for the bound, ok
- assert!(verify_circuit_unsafe::(Fq::from(4), Fq::from(3), 3).is_ok());
+ assert!(verify_circuit_unsafe::(Fr::from(4), Fr::from(3), 3).is_ok());
// Insufficient number of bits for the input, but this is not detected by the
// unsafety of the circuit (compare with the last example below)
- // Note that -Fq::one() is corresponds to q - 1 > bound
- assert!(verify_circuit_unsafe::(Fq::from(4), -Fq::one(), 3).is_ok());
+ // Note that -Fr::one() is corresponds to q - 1 > bound
+ assert!(verify_circuit_unsafe::(Fr::from(4), -Fr::one(), 3).is_ok());
println!("Unsafe circuit OK");
println!("Executing safe circuit...");
// Typical example, ok
- assert!(verify_circuit_safe::(Fq::from(17), Fq::from(9), 10).is_ok());
+ assert!(verify_circuit_safe::(Fr::from(17), Fr::from(9), 10).is_ok());
// Typical example, err
- assert!(verify_circuit_safe::(Fq::from(17), Fq::from(20), 10).is_err());
+ assert!(verify_circuit_safe::(Fr::from(17), Fr::from(20), 10).is_err());
// Edge case, err
- assert!(verify_circuit_safe::(Fq::from(4), Fq::from(4), 10).is_err());
+ assert!(verify_circuit_safe::(Fr::from(4), Fr::from(4), 10).is_err());
// Edge case, ok
- assert!(verify_circuit_safe::(Fq::from(4), Fq::from(3), 10).is_ok());
+ assert!(verify_circuit_safe::(Fr::from(4), Fr::from(3), 10).is_ok());
// Minimum number of bits for the bound, ok
- assert!(verify_circuit_safe::(Fq::from(4), Fq::from(3), 3).is_ok());
+ assert!(verify_circuit_safe::(Fr::from(4), Fr::from(3), 3).is_ok());
// Insufficient number of bits for the input, err (compare with the last example
// above).
- // Note that -Fq::one() is corresponds to q - 1 > bound
- assert!(verify_circuit_safe::(Fq::from(4), -Fq::one(), 3).is_err());
+ // Note that -Fr::one() is corresponds to q - 1 > bound
+ assert!(verify_circuit_safe::(Fr::from(4), -Fr::one(), 3).is_err());
println!("Safe circuit OK");
}
diff --git a/src/bellpepper/mod.rs b/src/bellpepper/mod.rs
index bc2b5b7..71ed2cd 100644
--- a/src/bellpepper/mod.rs
+++ b/src/bellpepper/mod.rs
@@ -3,43 +3,41 @@
//! [Bellperson]: https://github.com/filecoin-project/bellperson
pub mod r1cs;
-pub mod shape_cs;
-pub mod solver;
-pub mod test_shape_cs;
+// pub mod solver;
+
+// In Arkworks, shape of R1CS is derived from ark_relations::r1cs::ConstraintSystem
+// pub mod shape_cs;
+// pub mod test_shape_cs;
#[cfg(test)]
mod tests {
- use crate::{
- bellpepper::{
- r1cs::{SpartanShape, SpartanWitness},
- shape_cs::ShapeCS,
- solver::SatisfyingAssignment,
- },
- traits::Group,
- };
- use bellpepper_core::{num::AllocatedNum, ConstraintSystem, SynthesisError};
- use ff::PrimeField;
+ use crate::{bellpepper::r1cs::SpartanWitness, traits::Group};
+
+ use crate::r1cs::{R1CSShape, R1CS};
+ use ark_ff::Field;
+ use ark_relations::r1cs::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
+
+ fn synthesize_alloc_bit(cs: &mut ConstraintSystem) -> Result<(), SynthesisError> {
+ // Allocate 'a' as a public input
+ let a_var = cs.new_input_variable(|| Ok(F::ONE))?;
+
+ // Enforce: a * (1 - a) = 0 (this ensures that this is an 0 or 1)
+ cs.enforce_constraint(
+ LinearCombination::from(a_var), // Left: a
+ LinearCombination::from(Variable::One) - a_var, // Right: 1 - a
+ LinearCombination::zero(), // Output: 0
+ )?;
+
+ // Allocate 'b' as a public input
+ let b_var = cs.new_input_variable(|| Ok(F::ONE))?;
+
+ // Enforce: b * (1 - b) = 0 (this ensures that b is 0 or 1)
+ cs.enforce_constraint(
+ LinearCombination::from(b_var), // Left: b
+ LinearCombination::from(Variable::One) - b_var, // Right: 1 - b
+ LinearCombination::zero(), // Output: 0
+ )?;
- fn synthesize_alloc_bit>(
- cs: &mut CS,
- ) -> Result<(), SynthesisError> {
- // get two bits as input and check that they are indeed bits
- let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::ONE))?;
- let _ = a.inputize(cs.namespace(|| "a is input"));
- cs.enforce(
- || "check a is 0 or 1",
- |lc| lc + CS::one() - a.get_variable(),
- |lc| lc + a.get_variable(),
- |lc| lc,
- );
- let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::ONE))?;
- let _ = b.inputize(cs.namespace(|| "b is input"));
- cs.enforce(
- || "check b is 0 or 1",
- |lc| lc + CS::one() - b.get_variable(),
- |lc| lc + b.get_variable(),
- |lc| lc,
- );
Ok(())
}
@@ -48,12 +46,16 @@ mod tests {
G: Group,
{
// First create the shape
- let mut cs: ShapeCS = ShapeCS::new();
+ let mut cs: ConstraintSystem = ConstraintSystem::new();
let _ = synthesize_alloc_bit(&mut cs);
- let (shape, ck) = cs.r1cs_shape();
+ let r1cs_cm = cs
+ .to_matrices()
+ .expect("Failed to convert constraint system to R1CS");
+ let shape: R1CSShape = R1CSShape::from(&r1cs_cm);
+ let ck = R1CS::commitment_key(&shape);
// Now get the assignment
- let mut cs: SatisfyingAssignment = SatisfyingAssignment::new();
+ let mut cs: ConstraintSystem = ConstraintSystem::new();
let _ = synthesize_alloc_bit(&mut cs);
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
@@ -63,7 +65,8 @@ mod tests {
#[test]
fn test_alloc_bit() {
- test_alloc_bit_with::();
- test_alloc_bit_with::();
+ // test_alloc_bit_with::();
+ // test_alloc_bit_with::();
+ test_alloc_bit_with::();
}
}
diff --git a/src/bellpepper/r1cs.rs b/src/bellpepper/r1cs.rs
index 62806a0..2283394 100644
--- a/src/bellpepper/r1cs.rs
+++ b/src/bellpepper/r1cs.rs
@@ -2,15 +2,13 @@
#![allow(non_snake_case)]
-use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment, test_shape_cs::TestShapeCS};
use crate::{
errors::SpartanError,
- r1cs::{R1CSInstance, R1CSShape, R1CSWitness, R1CS},
+ r1cs::{R1CSInstance, R1CSShape, R1CSWitness},
traits::Group,
CommitmentKey,
};
-use bellpepper_core::{Index, LinearCombination};
-use ff::PrimeField;
+use ark_relations::r1cs::ConstraintSystem;
/// `SpartanWitness` provide a method for acquiring an `R1CSInstance` and `R1CSWitness` from implementers.
pub trait SpartanWitness {
@@ -22,23 +20,25 @@ pub trait SpartanWitness {
) -> Result<(R1CSInstance, R1CSWitness), SpartanError>;
}
+// TODO: Currently not used, move some helper methods here? Or remove it?
/// `SpartanShape` provides methods for acquiring `R1CSShape` and `CommitmentKey` from implementers.
pub trait SpartanShape {
/// Return an appropriate `R1CSShape` and `CommitmentKey` structs.
fn r1cs_shape(&self) -> (R1CSShape, CommitmentKey);
}
-impl SpartanWitness for SatisfyingAssignment
-where
- G::Scalar: PrimeField,
+impl SpartanWitness for ConstraintSystem
+// TODO: Not sure I need that
+// where
+// G::Scalar: PrimeField,
{
fn r1cs_instance_and_witness(
&self,
shape: &R1CSShape,
ck: &CommitmentKey,
) -> Result<(R1CSInstance, R1CSWitness), SpartanError> {
- let W = R1CSWitness::::new(shape, &self.aux_assignment)?;
- let X = &self.input_assignment[1..];
+ let W = R1CSWitness::::new(shape, &self.witness_assignment)?;
+ let X = &self.instance_assignment[1..];
let comm_W = W.commit(ck);
@@ -47,91 +47,3 @@ where
Ok((instance, W))
}
}
-
-macro_rules! impl_spartan_shape {
- ( $name:ident) => {
- impl SpartanShape for $name
- where
- G::Scalar: PrimeField,
- {
- fn r1cs_shape(&self) -> (R1CSShape, CommitmentKey) {
- let mut A: Vec<(usize, usize, G::Scalar)> = Vec::new();
- let mut B: Vec<(usize, usize, G::Scalar)> = Vec::new();
- let mut C: Vec<(usize, usize, G::Scalar)> = Vec::new();
-
- let mut num_cons_added = 0;
- let mut X = (&mut A, &mut B, &mut C, &mut num_cons_added);
-
- let num_inputs = self.num_inputs();
- let num_constraints = self.num_constraints();
- let num_vars = self.num_aux();
-
- for constraint in self.constraints.iter() {
- add_constraint(
- &mut X,
- num_vars,
- &constraint.0,
- &constraint.1,
- &constraint.2,
- );
- }
-
- assert_eq!(num_cons_added, num_constraints);
-
- let S: R1CSShape = {
- // Don't count One as an input for shape's purposes.
- let res = R1CSShape::new(num_constraints, num_vars, num_inputs - 1, &A, &B, &C);
- res.unwrap()
- };
-
- let ck = R1CS::::commitment_key(&S);
-
- (S, ck)
- }
- }
- };
-}
-
-impl_spartan_shape!(ShapeCS);
-impl_spartan_shape!(TestShapeCS);
-
-fn add_constraint(
- X: &mut (
- &mut Vec<(usize, usize, S)>,
- &mut Vec<(usize, usize, S)>,
- &mut Vec<(usize, usize, S)>,
- &mut usize,
- ),
- num_vars: usize,
- a_lc: &LinearCombination,
- b_lc: &LinearCombination,
- c_lc: &LinearCombination,
-) {
- let (A, B, C, nn) = X;
- let n = **nn;
- let one = S::ONE;
-
- let add_constraint_component = |index: Index, coeff, V: &mut Vec<_>| {
- match index {
- Index::Input(idx) => {
- // Inputs come last, with input 0, reprsenting 'one',
- // at position num_vars within the witness vector.
- let i = idx + num_vars;
- V.push((n, i, one * coeff))
- }
- Index::Aux(idx) => V.push((n, idx, one * coeff)),
- }
- };
-
- for (index, coeff) in a_lc.iter() {
- add_constraint_component(index.0, coeff, A);
- }
- for (index, coeff) in b_lc.iter() {
- add_constraint_component(index.0, coeff, B)
- }
- for (index, coeff) in c_lc.iter() {
- add_constraint_component(index.0, coeff, C)
- }
-
- **nn += 1;
-}
diff --git a/src/bellpepper/shape_cs.rs b/src/bellpepper/shape_cs.rs
index 51646ff..46f7954 100644
--- a/src/bellpepper/shape_cs.rs
+++ b/src/bellpepper/shape_cs.rs
@@ -6,9 +6,9 @@ use std::{
};
use crate::traits::Group;
-use bellpepper_core::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
+use ark_ff::{Field, PrimeField};
+use ark_relations::r1cs::Variable;
use core::fmt::Write;
-use ff::{Field, PrimeField};
#[derive(Clone, Copy)]
struct OrderedVariable(Variable);
diff --git a/src/bellpepper/solver.rs b/src/bellpepper/solver.rs
index 8b1261c..ebe7015 100644
--- a/src/bellpepper/solver.rs
+++ b/src/bellpepper/solver.rs
@@ -1,9 +1,8 @@
//! Support for generating R1CS witness using bellperson.
use crate::traits::Group;
-use ff::{Field, PrimeField};
-
-use bellpepper_core::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
+use ark_ff::{AdditiveGroup, Field, PrimeField};
+use ark_relations::r1cs::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
/// A `ConstraintSystem` which calculates witness values for a concrete instance of an R1CS circuit.
pub struct SatisfyingAssignment
diff --git a/src/bellpepper/test_shape_cs.rs b/src/bellpepper/test_shape_cs.rs
index 988835f..03af624 100644
--- a/src/bellpepper/test_shape_cs.rs
+++ b/src/bellpepper/test_shape_cs.rs
@@ -7,9 +7,9 @@ use std::{
};
use crate::traits::Group;
-use bellpepper_core::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
+use ark_ff::{Field, PrimeField};
+use ark_relations::r1cs::Variable;
use core::fmt::Write;
-use ff::{Field, PrimeField};
#[derive(Clone, Copy)]
struct OrderedVariable(Variable);
diff --git a/src/digest.rs b/src/digest.rs
index c0b1e48..bf7b7d5 100644
--- a/src/digest.rs
+++ b/src/digest.rs
@@ -1,5 +1,5 @@
+use ark_ff::PrimeField;
use bincode::Options;
-use ff::PrimeField;
use serde::Serialize;
use sha3::{Digest, Sha3_256};
use std::io;
@@ -47,8 +47,8 @@ impl<'a, F: PrimeField, T: Digestible> DigestComputer<'a, F, T> {
});
// turn the bit vector into a scalar
- let mut digest = F::ZERO;
- let mut coeff = F::ONE;
+ let mut digest = F::zero();
+ let mut coeff = F::one();
for bit in bv {
if bit {
digest += coeff;
@@ -80,9 +80,8 @@ impl<'a, F: PrimeField, T: Digestible> DigestComputer<'a, F, T> {
#[cfg(test)]
mod tests {
- use ff::Field;
+ use ark_ff::Field;
use once_cell::sync::OnceCell;
- use pasta_curves::pallas;
use serde::{Deserialize, Serialize};
use crate::traits::Group;
@@ -115,7 +114,7 @@ mod tests {
}
}
- type G = pallas::Point;
+ type G = ark_bls12_381::G1Projective;
#[test]
fn test_digest_field_not_ingested_in_computation() {
@@ -123,7 +122,7 @@ mod tests {
// let's set up a struct with a weird digest field to make sure the digest computation does not depend of it
let oc = OnceCell::new();
- oc.set(::Scalar::ONE).unwrap();
+ oc.set(<::Scalar as Field>::ONE).unwrap();
let s2: S = S { i: 42, digest: oc };
diff --git a/src/lib.rs b/src/lib.rs
index b55f0f0..7e0d8e9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,18 +1,20 @@
//! This library implements Spartan, a high-speed SNARK.
#![deny(
- warnings,
- unused,
+ // TODO: Uncomment
+ // warnings,
+ // unused,
future_incompatible,
nonstandard_style,
rust_2018_idioms,
- missing_docs
+ // TODO: Uncomment
+ // missing_docs
)]
#![allow(non_snake_case)]
#![allow(clippy::type_complexity)]
#![forbid(unsafe_code)]
// private modules
-mod bellpepper;
+mod bellpepper; // TODO: Replace with arkworks module?
mod constants;
mod digest;
mod r1cs;
@@ -23,7 +25,7 @@ pub mod provider;
pub mod spartan;
pub mod traits;
-use bellpepper_core::Circuit;
+use ark_relations::r1cs::ConstraintSynthesizer;
use core::marker::PhantomData;
use errors::SpartanError;
use serde::{Deserialize, Serialize};
@@ -65,14 +67,14 @@ pub struct SNARK
where
G: Group,
S: RelaxedR1CSSNARKTrait,
- C: Circuit,
+ C: ConstraintSynthesizer,
{
snark: S, // snark proving the witness is satisfying
_p: PhantomData,
_p2: PhantomData,
}
-impl, C: Circuit> SNARK {
+impl, C: ConstraintSynthesizer> SNARK {
/// Produces prover and verifier keys for the direct SNARK
pub fn setup(circuit: C) -> Result<(ProverKey, VerifierKey), SpartanError> {
let (pk, vk) = S::setup(circuit)?;
@@ -99,7 +101,7 @@ impl, C: Circuit> SNARK = <::CE as CommitmentEngineTrait>::CommitmentKey;
+type CommitmentKey = <::CE as CommitmentEngineTrait>::CommitmentKey;
type Commitment = <::CE as CommitmentEngineTrait>::Commitment;
type CompressedCommitment = <<::CE as CommitmentEngineTrait>::Commitment as CommitmentTrait>::CompressedCommitment;
type CE = ::CE;
@@ -107,42 +109,48 @@ type CE = ::CE;
#[cfg(test)]
mod tests {
use super::*;
- use crate::provider::{bn256_grumpkin::bn256, secp_secq::secp256k1};
- use bellpepper_core::{num::AllocatedNum, ConstraintSystem, SynthesisError};
- use ff::PrimeField;
-
+ use ark_ff::PrimeField;
+ use ark_relations::lc;
+ use ark_relations::r1cs::{ConstraintSystemRef, LinearCombination, SynthesisError, Variable};
#[derive(Clone, Debug, Default)]
struct CubicCircuit {}
- impl Circuit for CubicCircuit
- where
- F: PrimeField,
- {
- fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> {
- // Consider a cubic equation: `x^3 + x + 5 = y`, where `x` and `y` are respectively the input and output.
- let x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(F::ONE + F::ONE))?;
- let x_sq = x.square(cs.namespace(|| "x_sq"))?;
- let x_cu = x_sq.mul(cs.namespace(|| "x_cu"), &x)?;
- let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
- Ok(x_cu.get_value().unwrap() + x.get_value().unwrap() + F::from(5u64))
- })?;
-
- cs.enforce(
- || "y = x^3 + x + 5",
- |lc| {
- lc + x_cu.get_variable()
- + x.get_variable()
- + CS::one()
- + CS::one()
- + CS::one()
- + CS::one()
- + CS::one()
- },
- |lc| lc + CS::one(),
- |lc| lc + y.get_variable(),
- );
-
- let _ = y.inputize(cs.namespace(|| "output"));
+ impl ConstraintSynthesizer for CubicCircuit {
+ fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> {
+ // Fixed toy values for testing
+ let x = F::from(2u64); // Example: x = 2
+ let y = F::from(15u64); // Example: y = 15 (2^3 + 2 + 5 = 15)
+
+ // 1. Allocate x^2 as an intermediate variable (witness)
+ let x_squared_var = cs.new_witness_variable(|| Ok(x * x))?;
+
+ // Enforce x^2 = x * x
+ cs.enforce_constraint(
+ lc!() + (x, Variable::One),
+ lc!() + (x, Variable::One),
+ lc!() + x_squared_var,
+ )?;
+
+ // 2. Allocate x^3 as another intermediate variable (witness)
+ let x_cubed_var = cs.new_witness_variable(|| Ok(x * x * x))?;
+
+ // Enforce x^3 = x^2 * x
+ cs.enforce_constraint(
+ lc!() + x_squared_var,
+ lc!() + (x, Variable::One),
+ lc!() + x_cubed_var,
+ )?;
+
+ // 3. Add the constraint: x^3 + x + 5 = y
+ let constant_five = F::from(5u64);
+ cs.enforce_constraint(
+ lc!() + x_cubed_var + (x, Variable::One) + (constant_five, Variable::One),
+ lc!() + Variable::One, // Identity multiplier for y
+ lc!() + (y, Variable::One),
+ )?;
+
+ // 4. Expose y as a public input
+ cs.new_input_variable(|| Ok(y))?;
Ok(())
}
@@ -150,24 +158,31 @@ mod tests {
#[test]
fn test_snark() {
- type G = pasta_curves::pallas::Point;
+ type G = ark_bls12_381::G1Projective;
type EE = crate::provider::ipa_pc::EvaluationEngine;
type S = crate::spartan::snark::RelaxedR1CSSNARK;
type Spp = crate::spartan::ppsnark::RelaxedR1CSSNARK;
- test_snark_with::();
- test_snark_with::();
-
- type G2 = bn256::Point;
- type EE2 = crate::provider::ipa_pc::EvaluationEngine;
- type S2 = crate::spartan::snark::RelaxedR1CSSNARK;
- type S2pp = crate::spartan::ppsnark::RelaxedR1CSSNARK;
- test_snark_with::();
- test_snark_with::();
-
- type G3 = secp256k1::Point;
- type EE3 = crate::provider::ipa_pc::EvaluationEngine;
- type S3 = crate::spartan::snark::RelaxedR1CSSNARK;
- type S3pp = crate::spartan::ppsnark::RelaxedR1CSSNARK;
+ // test_snark_with::(); // TODO
+ // test_snark_with::(); // TODO
+
+ // type G2 = bn256::Point;
+ // type EE2 = crate::provider::ipa_pc::EvaluationEngine;
+ // type S2 = crate::spartan::snark::RelaxedR1CSSNARK;
+ // type S2pp = crate::spartan::ppsnark::RelaxedR1CSSNARK;
+ // test_snark_with::();
+ // test_snark_with::();
+
+ // type G3 = secp256k1::Point;
+ // type EE3 = crate::provider::ipa_pc::EvaluationEngine;
+ // type S3 = crate::spartan::snark::RelaxedR1CSSNARK;
+ // type S3pp = crate::spartan::ppsnark::RelaxedR1CSSNARK;
+ // test_snark_with::();
+ // test_snark_with::();
+
+ type G3 = ark_bls12_381::G1Projective;
+ type EE3 = provider::ipa_pc::EvaluationEngine;
+ type S3 = spartan::snark::RelaxedR1CSSNARK;
+ type S3pp = spartan::ppsnark::RelaxedR1CSSNARK;
test_snark_with::();
test_snark_with::();
}
diff --git a/src/provider/ark.rs b/src/provider/ark.rs
new file mode 100644
index 0000000..6bbc8fe
--- /dev/null
+++ b/src/provider/ark.rs
@@ -0,0 +1,190 @@
+use crate::provider::keccak::Keccak256Transcript;
+use crate::provider::pedersen::CommitmentEngine;
+use crate::traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait};
+use ark_bls12_381::g1::Config as G1Config;
+use ark_bls12_381::{Fq, Fr, G1Affine, G1Projective};
+use ark_ec::short_weierstrass::SWCurveConfig;
+use ark_ec::{
+ hashing::{curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurveBasedHasher, HashToCurve},
+ short_weierstrass::Projective,
+};
+use ark_ec::{AffineRepr, CurveGroup, PrimeGroup, VariableBaseMSM};
+use ark_ff::field_hashers::DefaultFieldHasher;
+use ark_ff::PrimeField;
+use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
+use derive_more::Into;
+use num_bigint::BigInt;
+use num_traits::{Num, Zero};
+use serde::ser::SerializeStruct;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use sha2::Sha256;
+
+/// Compressed representation of BLS12-381 group elements
+#[derive(Clone, Copy, Debug, Eq, PartialEq, CanonicalDeserialize, CanonicalSerialize)]
+pub struct BLS12CompressedElement {
+ repr: [u8; 48],
+}
+
+impl Serialize for BLS12CompressedElement {
+ fn serialize(&self, serializer: S) -> Result
+ where
+ S: Serializer,
+ {
+ let mut state = serializer.serialize_struct("BLS12CompressedElement", 1)?;
+ state.serialize_field("repr", &self.repr.as_slice())?;
+ state.end()
+ }
+}
+
+impl<'de> Deserialize<'de> for BLS12CompressedElement {
+ fn deserialize(deserializer: D) -> Result
+ where
+ D: Deserializer<'de>,
+ {
+ let repr: [u8; 48] = {
+ let repr_vec = Vec::::deserialize(deserializer)?;
+ if repr_vec.len() != 48 {
+ return Err(serde::de::Error::custom(
+ "Invalid length for BLS12CompressedElement repr",
+ ));
+ }
+ let mut repr_arr = [0u8; 48];
+ repr_arr.copy_from_slice(&repr_vec);
+ repr_arr
+ };
+ Ok(BLS12CompressedElement::new(repr))
+ }
+}
+
+impl BLS12CompressedElement {
+ /// Creates a new `BLS12CompressedElement`
+ pub const fn new(repr: [u8; 48]) -> Self {
+ Self { repr }
+ }
+}
+
+impl TranscriptReprTrait for BLS12CompressedElement {
+ fn to_transcript_bytes(&self) -> Vec {
+ self.repr.to_vec()
+ }
+}
+
+impl TranscriptReprTrait for ark_bls12_381::Fq {
+ fn to_transcript_bytes(&self) -> Vec {
+ let mut serialized_data = Vec::new();
+ self
+ .serialize_compressed(&mut serialized_data)
+ .expect("Serialization failed");
+ serialized_data
+ }
+}
+
+impl TranscriptReprTrait for ark_bls12_381::Fr {
+ fn to_transcript_bytes(&self) -> Vec {
+ let mut serialized_data = Vec::new();
+ self
+ .serialize_compressed(&mut serialized_data)
+ .expect("Serialization failed");
+ serialized_data
+ }
+}
+
+impl Group for G1Projective {
+ type Base = Fq;
+ type Scalar = Fr;
+ type CompressedGroupElement = BLS12CompressedElement;
+ type PreprocessedGroupElement = G1Affine;
+ type TE = Keccak256Transcript;
+ type CE = CommitmentEngine;
+
+ fn vartime_multiscalar_mul(
+ scalars: &[Self::Scalar],
+ bases: &[Self::PreprocessedGroupElement],
+ ) -> Self {
+ // TODO: Properly handle error
+ VariableBaseMSM::msm(bases, scalars).expect("Failed to perform MSM")
+ }
+
+ fn compress(&self) -> Self::CompressedGroupElement {
+ let mut repr = Vec::new();
+ self
+ .into_affine()
+ .serialize_compressed(&mut repr)
+ .expect("Serialization should not fail");
+ BLS12CompressedElement::new(
+ repr
+ .try_into()
+ .expect("Serialized data has incorrect length"),
+ )
+ }
+
+ fn preprocessed(&self) -> Self::PreprocessedGroupElement {
+ self.into_affine()
+ }
+
+ // TODO: This is not actually a label "from_uniform_bytes", fix it
+ fn from_label(label: &[u8], n: usize) -> Vec {
+ let domain_separator = b"from_uniform_bytes";
+ // TODO: Doesn't work with sha3::Shake256, which was originally used here, what do?
+ let hasher = MapToCurveBasedHasher::<
+ Projective,
+ DefaultFieldHasher,
+ WBMap,
+ >::new(domain_separator)
+ .expect("Failed to create MapToCurveBasedHasher");
+
+ // Generate `n` curve points from the label
+ (0..n)
+ .map(|i| {
+ let input = [label, &i.to_be_bytes()].concat();
+ hasher.hash(&input).expect("Failed to hash to curve")
+ })
+ .collect()
+ }
+
+ fn to_coordinates(&self) -> (Self::Base, Self::Base, bool) {
+ let affine = self.into_affine();
+ if affine.is_zero() {
+ (Self::Base::zero(), Self::Base::zero(), true)
+ } else {
+ let coords = affine
+ .xy()
+ .expect("Point is not at infinity; coordinates must exist");
+ (coords.0, coords.1, false)
+ }
+ }
+
+ fn zero() -> Self {
+ todo!()
+ }
+ fn get_generator() -> Self {
+ G1Projective::generator()
+ }
+
+ fn get_curve_params() -> (Self::Base, Self::Base, BigInt) {
+ let a = ark_bls12_381::g1::Config::COEFF_A;
+ let b = ark_bls12_381::g1::Config::COEFF_B;
+ let order = BigInt::from_str_radix(
+ "52435875175126190479447740508185965837690552500527637822603658699938581184512",
+ 10,
+ )
+ .unwrap();
+ (a, b, order)
+ }
+}
+
+impl CompressedGroup for BLS12CompressedElement {
+ type GroupElement = G1Projective;
+
+ fn decompress(&self) -> Option {
+ G1Affine::deserialize_compressed(&self.repr[..])
+ .ok()
+ .map(Into::into)
+ }
+}
+
+impl PrimeFieldExt for Fr {
+ fn from_uniform(bytes: &[u8]) -> Self {
+ Self::from_be_bytes_mod_order(bytes.try_into().unwrap())
+ }
+}
diff --git a/src/provider/ark_serde.rs b/src/provider/ark_serde.rs
new file mode 100644
index 0000000..5abc775
--- /dev/null
+++ b/src/provider/ark_serde.rs
@@ -0,0 +1,36 @@
+//! Implements serialization helpers for compatibility with ark-serialize
+
+use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
+use serde::{Deserialize, Deserializer, Serializer};
+use serde_with::{DeserializeAs, SerializeAs};
+
+pub struct Canonical(std::marker::PhantomData);
+
+impl SerializeAs for Canonical
+where
+ T: CanonicalSerialize,
+{
+ fn serialize_as(source: &T, serializer: S) -> Result
+ where
+ S: Serializer,
+ {
+ let mut buffer = Vec::new();
+ source
+ .serialize_compressed(&mut buffer)
+ .map_err(serde::ser::Error::custom)?;
+ serializer.serialize_bytes(&buffer)
+ }
+}
+
+impl<'de, T> DeserializeAs<'de, T> for Canonical
+where
+ T: CanonicalDeserialize,
+{
+ fn deserialize_as(deserializer: D) -> Result
+ where
+ D: Deserializer<'de>,
+ {
+ let bytes: Vec = Deserialize::deserialize(deserializer)?;
+ T::deserialize_compressed(&*bytes).map_err(serde::de::Error::custom)
+ }
+}
diff --git a/src/provider/bn256_grumpkin.rs b/src/provider/bn256_grumpkin.rs
index eb3fc9f..1c0c884 100644
--- a/src/provider/bn256_grumpkin.rs
+++ b/src/provider/bn256_grumpkin.rs
@@ -1,19 +1,8 @@
//! This module implements the Spartan traits for `bn256::Point`, `bn256::Scalar`, `grumpkin::Point`, `grumpkin::Scalar`.
-use crate::{
- impl_traits,
- provider::{cpu_best_multiexp, keccak::Keccak256Transcript, pedersen::CommitmentEngine},
- traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait},
-};
-use digest::{ExtendableOutput, Update};
-use ff::{FromUniformBytes, PrimeField};
-use group::{cofactor::CofactorCurveAffine, Curve, Group as AnotherGroup, GroupEncoding};
-use num_bigint::BigInt;
-use num_traits::Num;
+use crate::traits::{Group, TranscriptReprTrait};
// Remove this when https://github.com/zcash/pasta_curves/issues/41 resolves
-use pasta_curves::arithmetic::{CurveAffine, CurveExt};
-use rayon::prelude::*;
-use sha3::Shake256;
-use std::io::Read;
+use crate::impl_traits;
+use group::ff::PrimeField;
use halo2curves::bn256::{
G1Affine as Bn256Affine, G1Compressed as Bn256Compressed, G1 as Bn256Point,
@@ -21,6 +10,15 @@ use halo2curves::bn256::{
use halo2curves::grumpkin::{
G1Affine as GrumpkinAffine, G1Compressed as GrumpkinCompressed, G1 as GrumpkinPoint,
};
+use pasta_curves::arithmetic::{CurveAffine, CurveExt};
+use rayon::prelude::*;
+use sha3::Shake256;
+use std::io::Read;
+use ark_ec::CurveGroup;
+use crate::provider::keccak::Keccak256Transcript;
+use crate::provider::pedersen::CommitmentEngine;
+use crate::provider::AffineRepr;
+use crate::provider::VariableBaseMSM;
/// Re-exports that give access to the standard aliases used in the code base, for bn256
pub mod bn256 {
@@ -66,6 +64,8 @@ impl_traits!(
#[cfg(test)]
mod tests {
+ use digest::{ExtendableOutput, Update};
+ use group::Curve;
use super::*;
type G = bn256::Point;
diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs
index 413ae47..14125a8 100644
--- a/src/provider/ipa_pc.rs
+++ b/src/provider/ipa_pc.rs
@@ -1,5 +1,6 @@
//! This module implements `EvaluationEngine` using an IPA-based polynomial commitment scheme
#![allow(clippy::too_many_arguments)]
+use crate::provider::ark_serde::Canonical;
use crate::{
errors::SpartanError,
provider::pedersen::CommitmentKeyExtTrait,
@@ -11,10 +12,11 @@ use crate::{
},
Commitment, CommitmentKey, CompressedCommitment, CE,
};
+use ark_ff::{AdditiveGroup, Field};
use core::iter;
-use ff::Field;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
use std::marker::PhantomData;
/// Provides an implementation of the prover key
@@ -152,11 +154,13 @@ impl InnerProductWitness {
}
/// An inner product argument
+#[serde_as]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct InnerProductArgument {
L_vec: Vec>,
R_vec: Vec>,
+ #[serde_as(as = "Canonical")]
a_hat: G::Scalar,
}
@@ -235,7 +239,7 @@ where
transcript.absorb(b"R", &R);
let r = transcript.squeeze(b"r")?;
- let r_inverse = r.invert().unwrap();
+ let r_inverse = r.inverse().unwrap();
// fold the left half and the right half
let a_vec_folded = a_vec[0..n / 2]
@@ -324,7 +328,7 @@ where
}
// compute the inverse once for all entries
- acc = acc.invert().unwrap();
+ acc = acc.inverse().unwrap();
let mut inv = vec![G::Scalar::ZERO; v.len()];
for i in 0..v.len() {
diff --git a/src/provider/keccak.rs b/src/provider/keccak.rs
index 2046072..6858564 100644
--- a/src/provider/keccak.rs
+++ b/src/provider/keccak.rs
@@ -99,11 +99,11 @@ impl TranscriptEngineTrait for Keccak256Transcript {
#[cfg(test)]
mod tests {
use crate::{
- provider::bn256_grumpkin::bn256,
- provider::{self, keccak::Keccak256Transcript, secp_secq},
+ provider::keccak::Keccak256Transcript,
traits::{Group, PrimeFieldExt, TranscriptEngineTrait, TranscriptReprTrait},
};
- use ff::PrimeField;
+ use ark_serialize::CanonicalSerialize;
+ use bincode::Options;
use rand::Rng;
use sha3::{Digest, Keccak256};
@@ -120,7 +120,9 @@ mod tests {
// make a challenge
let c1: ::Scalar = transcript.squeeze(b"c1").unwrap();
- assert_eq!(hex::encode(c1.to_repr().as_ref()), expected_h1);
+ let mut buf = Vec::new();
+ c1.serialize_compressed(&mut buf).unwrap();
+ assert_eq!(hex::encode(buf), expected_h1);
// a scalar
let s3 = ::Scalar::from(128u64);
@@ -130,24 +132,31 @@ mod tests {
// make a challenge
let c2: ::Scalar = transcript.squeeze(b"c2").unwrap();
- assert_eq!(hex::encode(c2.to_repr().as_ref()), expected_h2);
+ let mut buf = Vec::new();
+ c2.serialize_compressed(&mut buf).unwrap();
+ assert_eq!(hex::encode(buf), expected_h2);
}
#[test]
fn test_keccak_transcript() {
- test_keccak_transcript_with::(
- "5ddffa8dc091862132788b8976af88b9a2c70594727e611c7217ba4c30c8c70a",
- "4d4bf42c065870395749fa1c4fb641df1e0d53f05309b03d5b1db7f0be3aa13d",
- );
-
- test_keccak_transcript_with::(
- "9fb71e3b74bfd0b60d97349849b895595779a240b92a6fae86bd2812692b6b0e",
- "bfd4c50b7d6317e9267d5d65c985eb455a3561129c0b3beef79bfc8461a84f18",
- );
-
- test_keccak_transcript_with::(
- "9723aafb69ec8f0e9c7de756df0993247d98cf2b2f72fa353e3de654a177e310",
- "a6a90fcb6e1b1a2a2f84c950ef1510d369aea8e42085f5c629bfa66d00255f25",
+ // test_keccak_transcript_with::(
+ // "5ddffa8dc091862132788b8976af88b9a2c70594727e611c7217ba4c30c8c70a",
+ // "4d4bf42c065870395749fa1c4fb641df1e0d53f05309b03d5b1db7f0be3aa13d",
+ // );
+
+ // test_keccak_transcript_with::(
+ // "9fb71e3b74bfd0b60d97349849b895595779a240b92a6fae86bd2812692b6b0e",
+ // "bfd4c50b7d6317e9267d5d65c985eb455a3561129c0b3beef79bfc8461a84f18",
+ // );
+
+ // test_keccak_transcript_with::(
+ // "9723aafb69ec8f0e9c7de756df0993247d98cf2b2f72fa353e3de654a177e310",
+ // "a6a90fcb6e1b1a2a2f84c950ef1510d369aea8e42085f5c629bfa66d00255f25",
+ // );
+
+ test_keccak_transcript_with::(
+ "4231f8722433b9500d7ae8e7743102d4ecc07d34bb887dc9aa11697b9c72f403",
+ "cc0b9d88915cf5a5568368c96882c89f99334877b1dee1363ce66af7f42c8d53",
);
}
@@ -236,15 +245,20 @@ mod tests {
let c1: ::Scalar = transcript.squeeze(b"c1").unwrap();
let c1_bytes = squeeze_for_testing(&manual_transcript[..], 0u16, initial_state, b"c1");
- let to_hex = |g: G::Scalar| hex::encode(g.to_repr().as_ref());
+ let to_hex = |g: G::Scalar| {
+ let mut buf = Vec::new();
+ g.serialize_compressed(&mut buf).unwrap();
+ hex::encode(buf)
+ };
assert_eq!(to_hex(c1), to_hex(G::Scalar::from_uniform(&c1_bytes)));
}
#[test]
fn test_keccak_transcript_incremental_vs_explicit() {
- test_keccak_transcript_incremental_vs_explicit_with::