zksync_solidity_vk_codegen 0.32.10

ZKsync solidity codegen for vks
mod circuits;
mod generate;
mod serialize;

pub use generate::{generate, Encoding, MainGateType};

use ethereum_types::U256;
use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr};
use franklin_crypto::bellman::pairing::ff::*;
use franklin_crypto::bellman::pairing::*;
use franklin_crypto::bellman::plonk::better_better_cs::cs::Circuit;
use franklin_crypto::bellman::plonk::better_better_cs::gates::selector_optimized_with_d_next::SelectorOptimizedWidth4MainGateWithDNext;
use franklin_crypto::bellman::plonk::better_better_cs::proof::Proof;
use franklin_crypto::bellman::plonk::better_better_cs::setup::VerificationKey;

use crate::circuits::DummyCircuit;

fn render_scalar_to_hex<F: PrimeField>(el: &F) -> String {
    let mut buff = vec![];
    let repr = el.into_repr();
    repr.write_be(&mut buff).unwrap();

    format!("0x{}", hex::encode(buff))
}

fn render_g1_affine_to_hex<E: Engine>(point: &E::G1Affine) -> [String; 2] {
    if <E::G1Affine as CurveAffine>::is_zero(point) {
        return ["0x0".to_owned(), "0x0".to_owned()];
    }

    let (x, y) = <E::G1Affine as CurveAffine>::into_xy_unchecked(*point);
    [render_scalar_to_hex(&x), render_scalar_to_hex(&y)]
}

fn render_g2_affine_to_hex(point: &<bn256::Bn256 as Engine>::G2Affine) -> [String; 4] {
    if <<bn256::Bn256 as Engine>::G2Affine as CurveAffine>::is_zero(point) {
        return ["0x0".to_owned(), "0x0".to_owned(), "0x0".to_owned(), "0x0".to_owned()];
    }

    let (x, y) = <<bn256::Bn256 as Engine>::G2Affine as CurveAffine>::into_xy_unchecked(*point);

    [render_scalar_to_hex(&x.c0), render_scalar_to_hex(&x.c1), render_scalar_to_hex(&y.c0), render_scalar_to_hex(&y.c1)]
}

fn serialize_g1_for_ethereum(point: &<bn256::Bn256 as Engine>::G1Affine) -> (U256, U256) {
    if <<bn256::Bn256 as Engine>::G1Affine as CurveAffine>::is_zero(point) {
        return (U256::zero(), U256::zero());
    }
    let uncompressed = point.into_uncompressed();

    let (x, y) = <<bn256::Bn256 as Engine>::G1Affine as CurveAffine>::into_xy_unchecked(*point);
    let _ = <<bn256::Bn256 as Engine>::G1Affine as CurveAffine>::from_xy_checked(x, y).unwrap();

    let mut buffer = [0u8; 32];
    x.into_repr().write_be(&mut buffer[..]).unwrap();
    let x = U256::from_big_endian(&buffer);

    let mut buffer = [0u8; 32];
    y.into_repr().write_be(&mut buffer[..]).unwrap();
    let y = U256::from_big_endian(&buffer);

    (x, y)
}

fn serialize_fe_for_ethereum(field_element: &Fr) -> U256 {
    let mut be_bytes = [0u8; 32];
    field_element.into_repr().write_be(&mut be_bytes[..]).expect("get new root BE bytes");
    U256::from_big_endian(&be_bytes[..])
}

pub fn serialize_proof<T: Circuit<Bn256>>(proof: &Proof<Bn256, T>) -> (Vec<U256>, Vec<U256>) {
    let mut inputs = vec![];
    for input in proof.inputs.iter() {
        inputs.push(serialize_fe_for_ethereum(&input));
    }
    let mut serialized_proof = vec![];

    for c in proof.state_polys_commitments.iter() {
        let (x, y) = serialize_g1_for_ethereum(&c);
        serialized_proof.push(x);
        serialized_proof.push(y);
    }

    let (x, y) = serialize_g1_for_ethereum(&proof.copy_permutation_grand_product_commitment);
    serialized_proof.push(x);
    serialized_proof.push(y);

    let (x, y) = serialize_g1_for_ethereum(&proof.lookup_s_poly_commitment.unwrap());
    serialized_proof.push(x);
    serialized_proof.push(y);

    let (x, y) = serialize_g1_for_ethereum(&proof.lookup_grand_product_commitment.unwrap());
    serialized_proof.push(x);
    serialized_proof.push(y);

    for c in proof.quotient_poly_parts_commitments.iter() {
        let (x, y) = serialize_g1_for_ethereum(&c);
        serialized_proof.push(x);
        serialized_proof.push(y);
    }

    assert_eq!(proof.state_polys_openings_at_z.len(), 4);
    for c in proof.state_polys_openings_at_z.iter() {
        serialized_proof.push(serialize_fe_for_ethereum(&c));
    }

    assert_eq!(proof.state_polys_openings_at_dilations.len(), 1);
    for (_, _, c) in proof.state_polys_openings_at_dilations.iter() {
        serialized_proof.push(serialize_fe_for_ethereum(&c));
    }

    assert_eq!(proof.gate_setup_openings_at_z.len(), 0);
    for (_, _, c) in proof.gate_setup_openings_at_z.iter() {
        serialized_proof.push(serialize_fe_for_ethereum(&c));
    }

    assert_eq!(proof.gate_selectors_openings_at_z.len(), 1);
    for (_, c) in proof.gate_selectors_openings_at_z.iter() {
        serialized_proof.push(serialize_fe_for_ethereum(&c));
    }

    for c in proof.copy_permutation_polys_openings_at_z.iter() {
        serialized_proof.push(serialize_fe_for_ethereum(&c));
    }

    serialized_proof.push(serialize_fe_for_ethereum(&proof.copy_permutation_grand_product_opening_at_z_omega));
    serialized_proof.push(serialize_fe_for_ethereum(&proof.lookup_s_poly_opening_at_z_omega.unwrap()));
    serialized_proof.push(serialize_fe_for_ethereum(&proof.lookup_grand_product_opening_at_z_omega.unwrap()));
    serialized_proof.push(serialize_fe_for_ethereum(&proof.lookup_t_poly_opening_at_z.unwrap()));
    serialized_proof.push(serialize_fe_for_ethereum(&proof.lookup_t_poly_opening_at_z_omega.unwrap()));
    serialized_proof.push(serialize_fe_for_ethereum(&proof.lookup_selector_poly_opening_at_z.unwrap()));
    serialized_proof.push(serialize_fe_for_ethereum(&proof.lookup_table_type_poly_opening_at_z.unwrap()));
    serialized_proof.push(serialize_fe_for_ethereum(&proof.quotient_poly_opening_at_z));
    serialized_proof.push(serialize_fe_for_ethereum(&proof.linearization_poly_opening_at_z));

    let (x, y) = serialize_g1_for_ethereum(&proof.opening_proof_at_z);
    serialized_proof.push(x);
    serialized_proof.push(y);

    let (x, y) = serialize_g1_for_ethereum(&proof.opening_proof_at_z_omega);
    serialized_proof.push(x);
    serialized_proof.push(y);

    dbg!(&serialized_proof.len());

    (inputs, serialized_proof)
}

#[test]
#[ignore] // TODO(ignored-test): Failure.
fn render_simple_proof() {
    use franklin_crypto::bellman::pairing::bn256::*;

    let mut reader = std::io::BufReader::with_capacity(1 << 24, std::fs::File::open("../data/optimized/scheduler_proof.key").unwrap());
    let proof = Proof::<Bn256, DummyCircuit>::read(&mut reader).unwrap();
    let (inputs, proof) = serialize_proof(&proof);

    println!("Inputs");
    let mut vec = vec![];
    for i in inputs.into_iter() {
        vec.push(format!("\"{}\"", i));
    }
    println!("[{}]", vec.join(","));

    println!("Proof");
    let mut vec = vec![];
    for i in proof.into_iter() {
        vec.push(format!("\"{}\"", i));
    }

    println!("[{}]", vec.join(","));
}