Feature/nova ivc (#36)

* Implement Nova IVC's new & prove_step methods

Implement Nova IVC's new & prove_step methods (without CycleFold part yet)

* transcript.absorb_point err handling, and update C.xy() usage

* add transcript usage to IVC prove, add NovaTranscript trait extending Transcript trait, refactor NIFS.P to allow absorbing in transcript inbetween

* Implement Nova's IVC.V method (without CycleFold part yet)

* clippy lints

* move challenge r computation in-circuit

* reuse computed points with coordinates over CF (non-native) to save constraints in AugmentedFCircuit

(constraint count went down ~6k)

* rm 128 bit constant

* add params to Errors

* Updates from review suggestions. Additionally refactored nova/nifs fold, and rm transcript from nova/IVC.

- Updates from PR suggestions
- Additionally updated:
  - in nova/nifs.rs: reuse folded_committed_instance for verify_folded_instance, computationally is the same, but reusing the same code so avoiding duplication and having an error on one of the two versions.
  - in nova/ivc.rs: remove transcript from IVC (not needed, it uses the RO)
This commit is contained in:
2023-11-24 11:15:14 +01:00
committed by GitHub
parent 6d919d7a5b
commit 905ba44d8d
15 changed files with 663 additions and 174 deletions

View File

@@ -1,3 +1,4 @@
use crate::Error;
use ark_ec::CurveGroup;
use ark_std::fmt::Debug;
@@ -9,7 +10,7 @@ pub trait Transcript<C: CurveGroup> {
fn new(config: &Self::TranscriptConfig) -> Self;
fn absorb(&mut self, v: &C::ScalarField);
fn absorb_vec(&mut self, v: &[C::ScalarField]);
fn absorb_point(&mut self, v: &C);
fn absorb_point(&mut self, v: &C) -> Result<(), Error>;
fn get_challenge(&mut self) -> C::ScalarField;
/// get_challenge_nbits returns a field element of size nbits
fn get_challenge_nbits(&mut self, nbits: usize) -> Vec<bool>;

View File

@@ -7,8 +7,10 @@ use ark_ec::{AffineRepr, CurveGroup, Group};
use ark_ff::{BigInteger, Field, PrimeField};
use ark_r1cs_std::{boolean::Boolean, fields::fp::FpVar};
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
use ark_std::{One, Zero};
use crate::transcript::Transcript;
use crate::Error;
/// PoseidonTranscript implements the Transcript trait using the Poseidon hash
pub struct PoseidonTranscript<C: CurveGroup>
@@ -34,8 +36,9 @@ where
fn absorb_vec(&mut self, v: &[C::ScalarField]) {
self.sponge.absorb(&v);
}
fn absorb_point(&mut self, p: &C) {
self.sponge.absorb(&prepare_point(p));
fn absorb_point(&mut self, p: &C) -> Result<(), Error> {
self.sponge.absorb(&prepare_point(p)?);
Ok(())
}
fn get_challenge(&mut self) -> C::ScalarField {
let c = self.sponge.squeeze_field_elements(1);
@@ -54,25 +57,27 @@ where
// Returns the point coordinates in Fr, so it can be absrobed by the transcript. It does not work
// over bytes in order to have a logic that can be reproduced in-circuit.
fn prepare_point<C: CurveGroup>(p: &C) -> Vec<C::ScalarField> {
let binding = p.into_affine();
let p_coords = &binding.xy().unwrap();
let x_bi = p_coords
.0
.to_base_prime_field_elements()
.next()
.expect("a")
.into_bigint();
let y_bi = p_coords
.1
.to_base_prime_field_elements()
.next()
.expect("a")
.into_bigint();
vec![
fn prepare_point<C: CurveGroup>(p: &C) -> Result<Vec<C::ScalarField>, Error> {
let affine = p.into_affine();
let xy_obj = &affine.xy();
let mut xy = (&C::BaseField::zero(), &C::BaseField::one());
if xy_obj.is_some() {
xy = xy_obj.unwrap();
}
let x_bi =
xy.0.to_base_prime_field_elements()
.next()
.expect("a")
.into_bigint();
let y_bi =
xy.1.to_base_prime_field_elements()
.next()
.expect("a")
.into_bigint();
Ok(vec![
C::ScalarField::from_le_bytes_mod_order(x_bi.to_bytes_le().as_ref()),
C::ScalarField::from_le_bytes_mod_order(y_bi.to_bytes_le().as_ref()),
]
])
}
/// PoseidonTranscriptVar implements the gadget compatible with PoseidonTranscript
@@ -166,7 +171,7 @@ pub mod tests {
#[test]
fn test_transcript_and_transcriptvar_nbits() {
let nbits = crate::constants::N_BITS_CHALLENGE;
let nbits = 128;
// use 'native' transcript
let config = poseidon_test_config::<Fq>();