mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-12 00:51:28 +01:00
Support for arbitrary arity for step circuit's IO (#107)
* support for arbitrary arity for F * revive MinRoot example * revive tests * revive ecdsa * remove unused code * use None instead of Some(1u32) * revive benches * fix clippy warning
This commit is contained in:
@@ -3,11 +3,6 @@ use bellperson::{
|
||||
ConstraintSystem, SynthesisError,
|
||||
};
|
||||
use ff::{PrimeField, PrimeFieldBits};
|
||||
use generic_array::typenum::U8;
|
||||
use neptune::{
|
||||
circuit::poseidon_hash,
|
||||
poseidon::{Poseidon, PoseidonConstants},
|
||||
};
|
||||
use nova_snark::{gadgets::ecc::AllocatedPoint, traits::circuit::StepCircuit};
|
||||
use subtle::Choice;
|
||||
|
||||
@@ -66,11 +61,6 @@ pub struct EcdsaCircuit<F>
|
||||
where
|
||||
F: PrimeField<Repr = [u8; 32]>,
|
||||
{
|
||||
pub z_r: Coordinate<F>,
|
||||
pub z_g: Coordinate<F>,
|
||||
pub z_pk: Coordinate<F>,
|
||||
pub z_c: F,
|
||||
pub z_s: F,
|
||||
pub r: Coordinate<F>,
|
||||
pub g: Coordinate<F>,
|
||||
pub pk: Coordinate<F>,
|
||||
@@ -78,7 +68,6 @@ where
|
||||
pub s: F,
|
||||
pub c_bits: Vec<Choice>,
|
||||
pub s_bits: Vec<Choice>,
|
||||
pub pc: PoseidonConstants<F, U8>,
|
||||
}
|
||||
|
||||
impl<F> EcdsaCircuit<F>
|
||||
@@ -88,42 +77,14 @@ where
|
||||
// Creates a new [`EcdsaCircuit<Fb, Fs>`]. The base and scalar field elements from the curve
|
||||
// field used by the signature are converted to scalar field elements from the cyclic curve
|
||||
// field used by the circuit.
|
||||
pub fn new<Fb, Fs>(
|
||||
num_steps: usize,
|
||||
signatures: &[EcdsaSignature<Fb, Fs>],
|
||||
pc: &PoseidonConstants<F, U8>,
|
||||
) -> (F, Vec<Self>)
|
||||
pub fn new<Fb, Fs>(num_steps: usize, signatures: &[EcdsaSignature<Fb, Fs>]) -> (Vec<F>, Vec<Self>)
|
||||
where
|
||||
Fb: PrimeField<Repr = [u8; 32]>,
|
||||
Fs: PrimeField<Repr = [u8; 32]> + PrimeFieldBits,
|
||||
{
|
||||
let mut z0 = F::zero();
|
||||
let mut z0 = Vec::new();
|
||||
let mut circuits = Vec::new();
|
||||
for i in 0..num_steps {
|
||||
let mut j = i;
|
||||
if i > 0 {
|
||||
j = i - 1
|
||||
};
|
||||
let z_signature = &signatures[j];
|
||||
let z_r = Coordinate::new(
|
||||
F::from_repr(z_signature.r.x.to_repr()).unwrap(),
|
||||
F::from_repr(z_signature.r.y.to_repr()).unwrap(),
|
||||
);
|
||||
|
||||
let z_g = Coordinate::new(
|
||||
F::from_repr(z_signature.g.x.to_repr()).unwrap(),
|
||||
F::from_repr(z_signature.g.y.to_repr()).unwrap(),
|
||||
);
|
||||
|
||||
let z_pk = Coordinate::new(
|
||||
F::from_repr(z_signature.pk.x.to_repr()).unwrap(),
|
||||
F::from_repr(z_signature.pk.y.to_repr()).unwrap(),
|
||||
);
|
||||
|
||||
let z_c = F::from_repr(z_signature.c.to_repr()).unwrap();
|
||||
let z_s = F::from_repr(z_signature.s.to_repr()).unwrap();
|
||||
|
||||
let signature = &signatures[i];
|
||||
for (i, signature) in signatures.iter().enumerate().take(num_steps) {
|
||||
let r = Coordinate::new(
|
||||
F::from_repr(signature.r.x.to_repr()).unwrap(),
|
||||
F::from_repr(signature.r.y.to_repr()).unwrap(),
|
||||
@@ -145,11 +106,6 @@ where
|
||||
let s = F::from_repr(signature.s.to_repr()).unwrap();
|
||||
|
||||
let circuit = EcdsaCircuit {
|
||||
z_r,
|
||||
z_g,
|
||||
z_pk,
|
||||
z_c,
|
||||
z_s,
|
||||
r,
|
||||
g,
|
||||
pk,
|
||||
@@ -157,13 +113,11 @@ where
|
||||
s,
|
||||
c_bits,
|
||||
s_bits,
|
||||
pc: pc.clone(),
|
||||
};
|
||||
circuits.push(circuit);
|
||||
|
||||
if i == 0 {
|
||||
z0 =
|
||||
Poseidon::<F, U8>::new_with_preimage(&[r.x, r.y, g.x, g.y, pk.x, pk.y, c, s], pc).hash();
|
||||
z0 = vec![r.x, r.y, g.x, g.y, pk.x, pk.y, c, s];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,36 +162,18 @@ impl<F> StepCircuit<F> for EcdsaCircuit<F>
|
||||
where
|
||||
F: PrimeField<Repr = [u8; 32]> + PrimeFieldBits,
|
||||
{
|
||||
fn arity(&self) -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
// Prove knowledge of the sk used to generate the Ecdsa signature (R,s)
|
||||
// with public key PK and message commitment c.
|
||||
// [s]G == R + [c]PK
|
||||
fn synthesize<CS: ConstraintSystem<F>>(
|
||||
&self,
|
||||
cs: &mut CS,
|
||||
z: AllocatedNum<F>,
|
||||
) -> Result<AllocatedNum<F>, SynthesisError> {
|
||||
let z_rx = AllocatedNum::alloc(cs.namespace(|| "z_rx"), || Ok(self.z_r.x))?;
|
||||
let z_ry = AllocatedNum::alloc(cs.namespace(|| "z_ry"), || Ok(self.z_r.y))?;
|
||||
let z_gx = AllocatedNum::alloc(cs.namespace(|| "z_gx"), || Ok(self.z_g.x))?;
|
||||
let z_gy = AllocatedNum::alloc(cs.namespace(|| "z_gy"), || Ok(self.z_g.y))?;
|
||||
let z_pkx = AllocatedNum::alloc(cs.namespace(|| "z_pkx"), || Ok(self.z_pk.x))?;
|
||||
let z_pky = AllocatedNum::alloc(cs.namespace(|| "z_pky"), || Ok(self.z_pk.y))?;
|
||||
let z_c = AllocatedNum::alloc(cs.namespace(|| "z_c"), || Ok(self.z_c))?;
|
||||
let z_s = AllocatedNum::alloc(cs.namespace(|| "z_s"), || Ok(self.z_s))?;
|
||||
|
||||
let z_hash = poseidon_hash(
|
||||
cs.namespace(|| "input hash"),
|
||||
vec![z_rx, z_ry, z_gx, z_gy, z_pkx, z_pky, z_c, z_s],
|
||||
&self.pc,
|
||||
)?;
|
||||
|
||||
cs.enforce(
|
||||
|| "z == z1",
|
||||
|lc| lc + z.get_variable(),
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + z_hash.get_variable(),
|
||||
);
|
||||
|
||||
_z: &[AllocatedNum<F>],
|
||||
) -> Result<Vec<AllocatedNum<F>>, SynthesisError> {
|
||||
let g = AllocatedPoint::alloc(
|
||||
cs.namespace(|| "G"),
|
||||
Some((self.g.x, self.g.y, self.g.is_infinity)),
|
||||
@@ -282,36 +218,12 @@ where
|
||||
let c = AllocatedNum::alloc(cs.namespace(|| "c"), || Ok(self.c))?;
|
||||
let s = AllocatedNum::alloc(cs.namespace(|| "s"), || Ok(self.s))?;
|
||||
|
||||
poseidon_hash(
|
||||
cs.namespace(|| "output hash"),
|
||||
vec![rx, ry, gx, gy, pkx, pky, c, s],
|
||||
&self.pc,
|
||||
)
|
||||
Ok(vec![rx, ry, gx, gy, pkx, pky, c, s])
|
||||
}
|
||||
|
||||
fn output(&self, z: &F) -> F {
|
||||
let z_hash = Poseidon::<F, U8>::new_with_preimage(
|
||||
&[
|
||||
self.z_r.x,
|
||||
self.z_r.y,
|
||||
self.z_g.x,
|
||||
self.z_g.y,
|
||||
self.z_pk.x,
|
||||
self.z_pk.y,
|
||||
self.z_c,
|
||||
self.z_s,
|
||||
],
|
||||
&self.pc,
|
||||
)
|
||||
.hash();
|
||||
debug_assert_eq!(z, &z_hash);
|
||||
|
||||
Poseidon::<F, U8>::new_with_preimage(
|
||||
&[
|
||||
self.r.x, self.r.y, self.g.x, self.g.y, self.pk.x, self.pk.y, self.c, self.s,
|
||||
],
|
||||
&self.pc,
|
||||
)
|
||||
.hash()
|
||||
fn output(&self, _z: &[F]) -> Vec<F> {
|
||||
vec![
|
||||
self.r.x, self.r.y, self.g.x, self.g.y, self.pk.x, self.pk.y, self.c, self.s,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ use ff::{
|
||||
derive::byteorder::{ByteOrder, LittleEndian},
|
||||
Field, PrimeField, PrimeFieldBits,
|
||||
};
|
||||
use generic_array::typenum::U8;
|
||||
use neptune::{poseidon::PoseidonConstants, Strength};
|
||||
use nova_snark::{
|
||||
traits::{circuit::TrivialTestCircuit, Group as Nova_Group},
|
||||
CompressedSNARK, PublicParams, RecursiveSNARK,
|
||||
@@ -165,22 +163,7 @@ fn main() {
|
||||
// produce public parameters
|
||||
println!("Generating public parameters...");
|
||||
|
||||
let pc = PoseidonConstants::<<G2 as Group>::Scalar, U8>::new_with_strength(Strength::Standard);
|
||||
let circuit_primary = EcdsaCircuit::<<G2 as Nova_Group>::Scalar> {
|
||||
z_r: Coordinate::new(
|
||||
<G2 as Nova_Group>::Scalar::zero(),
|
||||
<G2 as Nova_Group>::Scalar::zero(),
|
||||
),
|
||||
z_g: Coordinate::new(
|
||||
<G2 as Nova_Group>::Scalar::zero(),
|
||||
<G2 as Nova_Group>::Scalar::zero(),
|
||||
),
|
||||
z_pk: Coordinate::new(
|
||||
<G2 as Nova_Group>::Scalar::zero(),
|
||||
<G2 as Nova_Group>::Scalar::zero(),
|
||||
),
|
||||
z_c: <G2 as Nova_Group>::Scalar::zero(),
|
||||
z_s: <G2 as Nova_Group>::Scalar::zero(),
|
||||
r: Coordinate::new(
|
||||
<G2 as Nova_Group>::Scalar::zero(),
|
||||
<G2 as Nova_Group>::Scalar::zero(),
|
||||
@@ -197,7 +180,6 @@ fn main() {
|
||||
s: <G2 as Nova_Group>::Scalar::zero(),
|
||||
c_bits: vec![Choice::from(0u8); 256],
|
||||
s_bits: vec![Choice::from(0u8); 256],
|
||||
pc: pc.clone(),
|
||||
};
|
||||
|
||||
let circuit_secondary = TrivialTestCircuit::default();
|
||||
@@ -258,10 +240,10 @@ fn main() {
|
||||
let (z0_primary, circuits_primary) = EcdsaCircuit::<<G2 as Nova_Group>::Scalar>::new::<
|
||||
<G1 as Nova_Group>::Base,
|
||||
<G1 as Nova_Group>::Scalar,
|
||||
>(num_steps, &signatures(), &pc);
|
||||
>(num_steps, &signatures());
|
||||
|
||||
// Secondary circuit
|
||||
let z0_secondary = <G1 as Group>::Scalar::zero();
|
||||
let z0_secondary = vec![<G1 as Group>::Scalar::zero()];
|
||||
|
||||
// produce a recursive SNARK
|
||||
println!("Generating a RecursiveSNARK...");
|
||||
@@ -277,8 +259,8 @@ fn main() {
|
||||
recursive_snark,
|
||||
circuit_primary.clone(),
|
||||
circuit_secondary.clone(),
|
||||
z0_primary,
|
||||
z0_secondary,
|
||||
z0_primary.clone(),
|
||||
z0_secondary.clone(),
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
println!("RecursiveSNARK::prove_step {}: {:?}", i, result.is_ok());
|
||||
@@ -290,7 +272,7 @@ fn main() {
|
||||
|
||||
// verify the recursive SNARK
|
||||
println!("Verifying the RecursiveSNARK...");
|
||||
let res = recursive_snark.verify(&pp, num_steps, z0_primary, z0_secondary);
|
||||
let res = recursive_snark.verify(&pp, num_steps, z0_primary.clone(), z0_secondary.clone());
|
||||
println!("RecursiveSNARK::verify: {:?}", res.is_ok());
|
||||
assert!(res.is_ok());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user