Skip to content

Commit

Permalink
chore(fflonk): small updates for compression
Browse files Browse the repository at this point in the history
  • Loading branch information
saitima committed Sep 30, 2024
1 parent 92f069f commit 45c31fe
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 95 deletions.
11 changes: 6 additions & 5 deletions crates/fflonk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ edition = "2021"

[dependencies]
circuit_definitions = {git = "https://github.com/matter-labs/zksync-protocol", package = "circuit_definitions", branch = "si/fflonk"}
# circuit_definitions = {path = "../../../zksync-protocol/crates/circuit_definitions"}
# circuit_definitions = { path = "../../../zksync-protocol/crates/circuit_definitions" }
# circuit_definitions = "=0.150.5"
# franklin_crypto = {path = "../franklin-crypto", package = "franklin-crypto"}
num-bigint = {version = "0.4", features = ["serde"]}
num-bigint = { version = "0.4", features = ["serde"] }
num-traits = "0.2"
rand = "0.4"
serde = {version = "1", features = ["derive", "rc"]}
serde = { version = "1", features = ["derive", "rc"] }
serde_json = "1"
serde_derive = "1"
bincode = "1.3"
byteorder = "1"
ureq = "2.5"

[features]
default = ["sanity"]
sanity = []
default = ["sanity"]
sanity = []
67 changes: 58 additions & 9 deletions crates/fflonk/src/convenience.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bellman::plonk::better_better_cs::{
};
use byteorder::{BigEndian, ReadBytesExt};
use circuit_definitions::circuit_definitions::aux_layer::compression_modes::{CompressionTranscriptForWrapper, CompressionTreeHasherForWrapper};
use circuit_definitions::circuit_definitions::aux_layer::wrapper::ZkSyncCompressionWrapper;
use circuit_definitions::circuit_definitions::recursion_layer::{ZkSyncRecursionProof, ZkSyncRecursionVerificationKey};
use circuit_definitions::{
circuit_definitions::aux_layer::{
Expand Down Expand Up @@ -48,20 +49,22 @@ type CompressionTranscript = GoldilocksPoisedon2Transcript;
type CompressionTreeHasher = GoldilocksPoseidon2Sponge<AbsorptionModeOverwrite>;

pub const L1_VERIFIER_DOMAIN_SIZE_LOG: usize = 23;
pub const MAX_COMBINED_DEGREE_FACTOR: usize = 9;
type F = GoldilocksField;
type EXT = GoldilocksExt2;

pub fn init_crs(worker: &Worker, domain_size: usize, max_combined_degree: usize) -> Crs<Bn256, CrsForMonomialForm> {
pub fn init_crs(worker: &Worker, domain_size: usize) -> Crs<Bn256, CrsForMonomialForm> {
assert!(domain_size <= 1 << L1_VERIFIER_DOMAIN_SIZE_LOG);
let num_points = MAX_COMBINED_DEGREE_FACTOR * domain_size;
let mon_crs = if let Ok(crs_file_path) = std::env::var("CRS_FILE") {
println!("using crs file at {crs_file_path}");
let crs_file = std::fs::File::open(&crs_file_path).expect(&format!("crs file at {}", crs_file_path));
let mon_crs = Crs::<Bn256, CrsForMonomialForm>::read(crs_file).expect(&format!("read crs file at {}", crs_file_path));
assert!(max_combined_degree <= mon_crs.g1_bases.len());
assert!(num_points <= mon_crs.g1_bases.len());

mon_crs
} else {
Crs::<Bn256, CrsForMonomialForm>::non_power_of_two_crs_42(max_combined_degree, &worker)
Crs::<Bn256, CrsForMonomialForm>::non_power_of_two_crs_42(num_points, &worker)
};

mon_crs
Expand All @@ -80,6 +83,52 @@ pub fn init_crs_for_vk() -> Crs<Bn256, CrsForMonomialForm> {
mon_crs
}

pub fn init_snark_wrapper_circuit(path: &str) -> FflonkSnarkVerifierCircuit {
let compression_wrapper_mode = if let Ok(compression_wrapper_mode) = std::env::var("COMPRESSION_WRAPPER_MODE") {
compression_wrapper_mode.parse::<u8>().unwrap()
} else {
5u8
};
println!("Compression mode {}", compression_wrapper_mode);
let compression_proof_file_path = if let Ok(file_path) = std::env::var("COMPRESSION_PROOF_FILE") {
file_path
} else {
format!("{}/compression_wrapper_{compression_wrapper_mode}_proof.json", path)
};
println!("Reading proof file at {compression_proof_file_path}");
let compression_vk_file_path = if let Ok(file_path) = std::env::var("COMPRESSION_VK_FILE") {
file_path
} else {
format!("{}/compression_wrapper_{compression_wrapper_mode}_vk.json", path)
};
println!("Reading vk file at {compression_vk_file_path}");

let compression_proof_file = std::fs::File::open(compression_proof_file_path).unwrap();
let compression_proof: ZkSyncCompressionProofForWrapper = serde_json::from_reader(&compression_proof_file).unwrap();

let compression_vk_file = std::fs::File::open(compression_vk_file_path).unwrap();
let compression_vk: ZkSyncCompressionVerificationKeyForWrapper = serde_json::from_reader(&compression_vk_file).unwrap();

init_snark_wrapper_circuit_from_inputs(compression_wrapper_mode, compression_proof, compression_vk)
}

pub fn init_snark_wrapper_circuit_from_inputs(
compression_wrapper_mode: u8,
input_proof: ZkSyncCompressionProofForWrapper,
input_vk: ZkSyncCompressionVerificationKeyForWrapper,
) -> FflonkSnarkVerifierCircuit {
let wrapper_function = ZkSyncCompressionWrapper::from_numeric_circuit_type(compression_wrapper_mode);
let fixed_parameters = input_vk.fixed_parameters.clone();

FflonkSnarkVerifierCircuit {
witness: Some(input_proof),
vk: input_vk,
fixed_parameters,
transcript_params: (),
wrapper_function,
}
}

pub fn precompute_and_save_setup_for_fflonk_snark_circuit(circuit: &FflonkSnarkVerifierCircuit, worker: &Worker, output_blob_path: &str) {
let compression_wrapper_mode = circuit.wrapper_function.numeric_circuit_type();
println!("Compression mode: {compression_wrapper_mode}");
Expand All @@ -94,7 +143,7 @@ pub fn precompute_and_save_setup_for_fflonk_snark_circuit(circuit: &FflonkSnarkV
assert!(domain_size.is_power_of_two());
assert!(domain_size <= 1 << L1_VERIFIER_DOMAIN_SIZE_LOG);

let mon_crs = init_crs(&worker, domain_size, max_combined_degree);
let mon_crs = init_crs(&worker, domain_size);
let setup: FflonkSnarkVerifierCircuitSetup = FflonkSetup::create_setup(&setup_assembly, &worker, &mon_crs).expect("fflonk setup");
let vk = FflonkVerificationKey::from_setup(&setup, &mon_crs).unwrap();

Expand All @@ -121,9 +170,9 @@ pub fn prove_fflonk_snark_verifier_circuit_with_precomputation(

assert!(domain_size <= 1 << L1_VERIFIER_DOMAIN_SIZE_LOG);

let mon_crs = init_crs(&worker, domain_size, max_combined_degree);
let mon_crs = init_crs(&worker, domain_size);

let proof = crate::prover::create_proof::<_, FflonkSnarkVerifierCircuit, _, _, _, RollingKeccakTranscript<Fr>>(assembly, &worker, &precomputed_setup, &mon_crs, None).expect("proof");
let proof = crate::prover::create_proof::<_, FflonkSnarkVerifierCircuit, _, _, _, RollingKeccakTranscript<Fr>>(&assembly, &worker, &precomputed_setup, &mon_crs, None).expect("proof");
let valid = crate::verify::<_, _, RollingKeccakTranscript<Fr>>(&vk, &proof, None).unwrap();
assert!(valid, "proof verification fails");

Expand All @@ -143,11 +192,11 @@ pub fn prove_fflonk_snark_verifier_circuit_single_shot(circuit: &FflonkSnarkVeri

let max_combined_degree = compute_max_combined_degree_from_assembly::<_, _, _, _, FflonkSnarkVerifierCircuit>(&assembly);
println!("Max degree is {}", max_combined_degree);
let mon_crs = init_crs(&worker, domain_size, max_combined_degree);
let mon_crs = init_crs(&worker, domain_size);
let setup = FflonkSetup::create_setup(&assembly, &worker, &mon_crs).expect("setup");
let vk = FflonkVerificationKey::from_setup(&setup, &mon_crs).unwrap();

let proof = crate::prover::create_proof::<_, FflonkSnarkVerifierCircuit, _, _, _, RollingKeccakTranscript<Fr>>(assembly, &worker, &setup, &mon_crs, None).expect("proof");
let proof = crate::prover::create_proof::<_, FflonkSnarkVerifierCircuit, _, _, _, RollingKeccakTranscript<Fr>>(&assembly, &worker, &setup, &mon_crs, None).expect("proof");
let valid = crate::verify::<_, _, RollingKeccakTranscript<Fr>>(&vk, &proof, None).unwrap();
assert!(valid, "proof verification fails");

Expand Down Expand Up @@ -1051,7 +1100,7 @@ fn download_file(url: &str, output_file: &str) -> Result<(), ureq::Error> {
Ok(())
}

pub(crate) fn download_and_transform_ignition_transcripts(domain_size: usize) {
pub fn download_and_transform_ignition_transcripts(domain_size: usize) {
let transcripts_dir = std::env::var("IGNITION_TRANSCRIPT_PATH").unwrap_or("./".to_string());
let chunk_size = 5_040_000usize;
let num_chunks = domain_size.div_ceil(chunk_size);
Expand Down
3 changes: 2 additions & 1 deletion crates/fflonk/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![feature(generic_const_exprs)]
#![feature(allocator_api)]
pub use circuit_definitions;
pub use circuit_definitions::snark_wrapper::franklin_crypto;
use circuit_definitions::snark_wrapper::franklin_crypto::bellman::plonk::better_better_cs::{cs::PlonkCsWidth3Params, gates::naive_main_gate::NaiveMainGate};
pub use franklin_crypto::bellman;
Expand Down Expand Up @@ -31,7 +32,7 @@ pub use franklin_crypto::plonk::circuit::custom_rescue_gate::Rescue5CustomGate;

mod definitions;
pub use definitions::*;
mod prover;
pub mod prover;
use prover::*;
pub mod verifier;
pub use utils::*;
Expand Down
2 changes: 1 addition & 1 deletion crates/fflonk/src/prover.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::*;

pub fn create_proof<E: Engine, C: Circuit<E>, P: PlonkConstraintSystemParams<E>, MG: MainGate<E>, S: SynthesisMode, T: Transcript<<E as ScalarEngine>::Fr>>(
assembly: Assembly<E, P, MG, S>,
assembly: &Assembly<E, P, MG, S>,
worker: &Worker,
setup: &FflonkSetup<E, C>,
mon_crs: &Crs<E, CrsForMonomialForm>,
Expand Down
134 changes: 56 additions & 78 deletions crates/fflonk/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use circuit_definitions::snark_wrapper::franklin_crypto::{
bellman::{
use circuit_definitions::{
boojum::pairing::ff::Field,
snark_wrapper::franklin_crypto::bellman::{
bn256::{Bn256, Fr},
plonk::{
better_better_cs::{
cs::{Circuit, PlonkCsWidth3Params, SetupAssembly},
gates::naive_main_gate::NaiveMainGate,
},
commitments::transcript::keccak_transcript::RollingKeccakTranscript,
polynomials::Polynomial,
},
worker::Worker,
},
plonk::circuit::linear_combination::LinearCombination,
};
use circuit_definitions::{
boojum::pairing::ff::PrimeField,
Expand All @@ -22,6 +23,8 @@ use circuit_definitions::{
},
};

use crate::FflonkTestCircuit;

use super::convenience::*;

#[test]
Expand Down Expand Up @@ -137,41 +140,7 @@ fn verify_compression_wrapper_proof() {
#[ignore]
fn test_snark_circuit_with_naive_main_gate() {
let path = format!("./data/compression_schedule/hard");
let compression_wrapper_mode = if let Ok(compression_wrapper_mode) = std::env::var("COMPRESSION_WRAPPER_MODE") {
compression_wrapper_mode.parse::<u8>().unwrap()
} else {
5u8
};
println!("Compression mode {}", compression_wrapper_mode);
let compression_proof_file_path = if let Ok(file_path) = std::env::var("COMPRESSION_PROOF_FILE") {
file_path
} else {
format!("{}/compression_wrapper_{compression_wrapper_mode}_proof.json", path)
};
println!("Reading proof file at {compression_proof_file_path}");
let compression_vk_file_path = if let Ok(file_path) = std::env::var("COMPRESSION_VK_FILE") {
file_path
} else {
format!("{}/compression_wrapper_{compression_wrapper_mode}_vk.json", path)
};
println!("Reading vk file at {compression_vk_file_path}");

let compression_proof_file = std::fs::File::open(compression_proof_file_path).unwrap();
let compression_proof: ZkSyncCompressionProofForWrapper = serde_json::from_reader(&compression_proof_file).unwrap();

let compression_vk_file = std::fs::File::open(compression_vk_file_path).unwrap();
let compression_vk: ZkSyncCompressionVerificationKeyForWrapper = serde_json::from_reader(&compression_vk_file).unwrap();

let wrapper_function = ZkSyncCompressionWrapper::from_numeric_circuit_type(compression_wrapper_mode);
let fixed_parameters = compression_vk.fixed_parameters.clone();

let circuit = FflonkSnarkVerifierCircuit {
witness: Some(compression_proof),
vk: compression_vk,
fixed_parameters,
transcript_params: (),
wrapper_function,
};
let circuit = init_snark_wrapper_circuit(&path);
let worker = Worker::new();
let (proof, vk) = prove_fflonk_snark_verifier_circuit_single_shot(&circuit, &worker);

Expand Down Expand Up @@ -371,48 +340,12 @@ fn download_and_transform_crs() {
compression_wrapper_mode
);
// Step 1
let max_degree = crate::compute_max_combined_degree_from_assembly::<_, _, _, _, FflonkSnarkVerifierCircuit>(&assembly);
// let max_degree = crate::compute_max_combined_degree_from_assembly::<_, _, _, _, FflonkSnarkVerifierCircuit>(&assembly);
let max_degree = MAX_COMBINED_DEGREE_FACTOR * domain_size;
// Step 2-4
download_and_transform_ignition_transcripts(max_degree);
}

struct FflonkTestCircuit;

impl Circuit<Bn256> for FflonkTestCircuit {
type MainGate = NaiveMainGate;

fn synthesize<CS: circuit_definitions::snark_wrapper::franklin_crypto::bellman::plonk::better_better_cs::cs::ConstraintSystem<Bn256> + 'static>(
&self,
cs: &mut CS,
) -> Result<(), circuit_definitions::snark_wrapper::franklin_crypto::bellman::SynthesisError> {
use circuit_definitions::snark_wrapper::franklin_crypto::bellman::Field;
use circuit_definitions::snark_wrapper::franklin_crypto::plonk::circuit::allocated_num::Num;
let a = Fr::from_str(&65.to_string()).unwrap();
let b = Fr::from_str(&66.to_string()).unwrap();
let mut c = a;
c.add_assign(&b);

let a_var = Num::alloc(cs, Some(a))?;
let b_var = Num::alloc(cs, Some(b))?;
let c_var = Num::alloc(cs, Some(c))?;

for _ in 0..1 << 10 {
let mut lc = LinearCombination::zero();
lc.add_assign_number_with_coeff(&a_var, Fr::one());
lc.add_assign_number_with_coeff(&b_var, Fr::one());
let mut minus_one = Fr::one();
minus_one.negate();
lc.add_assign_number_with_coeff(&c_var, minus_one);

let _ = lc.into_num(cs)?;
}

let _input = cs.alloc_input(|| Ok(Fr::one()))?;

Ok(())
}
}

#[test]
#[ignore]
fn test_test_circuit_with_naive_main_gate() {
Expand All @@ -434,11 +367,56 @@ fn test_test_circuit_with_naive_main_gate() {

let max_combined_degree = compute_max_combined_degree_from_assembly::<_, _, _, _, FflonkTestCircuit>(&assembly);
println!("Max degree is {}", max_combined_degree);
let mon_crs = init_crs(&worker, domain_size, max_combined_degree);
let mon_crs = init_crs(&worker, domain_size);
let setup = FflonkSetup::create_setup(&assembly, &worker, &mon_crs).expect("setup");
let vk = FflonkVerificationKey::from_setup(&setup, &mon_crs).unwrap();
let vk_file = std::fs::File::create("/tmp/test_vk.json").unwrap();
serde_json::to_writer(&vk_file, &vk).unwrap();
println!("vk file saved");

let proof = crate::prover::create_proof::<_, FflonkTestCircuit, _, _, _, RollingKeccakTranscript<Fr>>(assembly, &worker, &setup, &mon_crs, None).expect("proof");
let proof = crate::prover::create_proof::<_, FflonkTestCircuit, _, _, _, RollingKeccakTranscript<Fr>>(&assembly, &worker, &setup, &mon_crs, None).expect("proof");
dbg!(&proof.commitments);
let valid = crate::verify::<_, _, RollingKeccakTranscript<Fr>>(&vk, &proof, None).unwrap();
assert!(valid, "proof verification fails");
}

#[test]
fn test_alternative_division() {
let worker = &Worker::new();
let domain_size = 1 << 2;
let degree = 2 * domain_size;

let expected_coeffs: Vec<_> = (0..degree).map(|el| Fr::from_str(&el.to_string()).unwrap()).collect();
let mut actual = Polynomial::from_coeffs_unpadded(expected_coeffs.clone()).unwrap();

let mut minus_two = Fr::one();
minus_two.negate();

let mut other = vec![Fr::zero(); 2 * domain_size];
other[0] = minus_two;
other[domain_size - 1] = Fr::one();
let other = Polynomial::from_coeffs(other).unwrap();

let coset_factor = Fr::multiplicative_generator();
let mut other_evals = other.coset_fft_for_generator(worker, coset_factor);
other_evals.batch_inversion(worker).unwrap();

for chunk_coeffs in actual.as_mut().chunks_mut(domain_size) {
let mut num = vec![Fr::zero(); 2 * domain_size];
num[..domain_size].copy_from_slice(chunk_coeffs);

let chunk = Polynomial::from_coeffs(num).unwrap();
let mut chunk_evals = chunk.coset_fft_for_generator(worker, coset_factor);
chunk_evals.mul_assign(worker, &other_evals);
// chunk_evals.bitreverse_enumeration(worker);
chunk_coeffs.copy_from_slice(chunk_evals.icoset_fft_for_generator(worker, &coset_factor).as_ref());
}

let mut actual_coeffs = vec![Fr::zero(); degree + 1];
assert_eq!(actual_coeffs.len(), actual.as_ref().len() + 1);

actual_coeffs[1..].copy_from_slice(actual.as_ref());
actual_coeffs[0].add_assign(&minus_two);

assert_eq!(expected_coeffs, actual_coeffs);
}
2 changes: 1 addition & 1 deletion crates/fflonk/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,7 @@ impl Circuit<Bn256> for FflonkTestCircuit {
let b_var = Num::alloc(cs, Some(b))?;
let c_var = Num::alloc(cs, Some(c))?;

for _ in 0..1 << 10 {
for _ in 0..1 << 5 {
let mut lc = LinearCombination::zero();
lc.add_assign_number_with_coeff(&a_var, Fr::one());
lc.add_assign_number_with_coeff(&b_var, Fr::one());
Expand Down

0 comments on commit 45c31fe

Please sign in to comment.