use crate::{
arkworks::{CamlFp, CamlGVesta},
field_vector::fp::CamlFpVector,
pasta_fp_plonk_index::{CamlPastaFpPlonkIndex, CamlPastaFpPlonkIndexPtr},
pasta_fp_plonk_verifier_index::CamlPastaFpPlonkVerifierIndex,
srs::fp::CamlFpSrs,
WithLagrangeBasis,
};
use ark_ec::AffineRepr;
use ark_ff::One;
use core::array;
use groupmap::GroupMap;
use kimchi::{
circuits::{
lookup::runtime_tables::{caml::CamlRuntimeTable, RuntimeTable},
polynomial::COLUMNS,
},
proof::{
PointEvaluations, ProofEvaluations, ProverCommitments, ProverProof, RecursionChallenge,
},
prover::caml::CamlProofWithPublic,
prover_index::ProverIndex,
verifier::{batch_verify, verify, Context},
verifier_index::VerifierIndex,
};
use mina_curves::pasta::{Fp, Fq, Pallas, Vesta, VestaParameters};
use mina_poseidon::{
constants::PlonkSpongeConstantsKimchi,
sponge::{DefaultFqSponge, DefaultFrSponge},
};
use poly_commitment::{
commitment::{CommitmentCurve, PolyComm},
ipa::OpeningProof,
};
use std::convert::TryInto;
type EFqSponge = DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>;
type EFrSponge = DefaultFrSponge<Fp, PlonkSpongeConstantsKimchi>;
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_create(
index: CamlPastaFpPlonkIndexPtr<'static>,
witness: Vec<CamlFpVector>,
runtime_tables: Vec<CamlRuntimeTable<CamlFp>>,
prev_challenges: Vec<CamlFp>,
prev_sgs: Vec<CamlGVesta>,
) -> Result<CamlProofWithPublic<CamlGVesta, CamlFp>, ocaml::Error> {
{
index
.as_ref()
.0
.srs
.with_lagrange_basis(index.as_ref().0.cs.domain.d1);
}
let prev = if prev_challenges.is_empty() {
Vec::new()
} else {
let challenges_per_sg = prev_challenges.len() / prev_sgs.len();
prev_sgs
.into_iter()
.map(Into::<Vesta>::into)
.enumerate()
.map(|(i, sg)| {
let chals = prev_challenges[(i * challenges_per_sg)..(i + 1) * challenges_per_sg]
.iter()
.map(Into::<Fp>::into)
.collect();
let comm = PolyComm::<Vesta> { chunks: vec![sg] };
RecursionChallenge { chals, comm }
})
.collect()
};
let witness: Vec<Vec<_>> = witness.iter().map(|x| (**x).clone()).collect();
let witness: [Vec<_>; COLUMNS] = witness
.try_into()
.map_err(|_| ocaml::Error::Message("the witness should be a column of 15 vectors"))?;
let index: &ProverIndex<Vesta, OpeningProof<Vesta>> = &index.as_ref().0;
let runtime_tables: Vec<RuntimeTable<Fp>> =
runtime_tables.into_iter().map(Into::into).collect();
let public_input = witness[0][0..index.cs.public].to_vec();
let runtime = unsafe { ocaml::Runtime::recover_handle() };
runtime.releasing_runtime(|| {
let group_map = GroupMap::<Fq>::setup();
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&runtime_tables,
index,
prev,
None,
&mut rand::rngs::OsRng,
)
.map_err(|e| ocaml::Error::Error(e.into()))?;
Ok((proof, public_input).into())
})
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_create_and_verify(
index: CamlPastaFpPlonkIndexPtr<'static>,
witness: Vec<CamlFpVector>,
runtime_tables: Vec<CamlRuntimeTable<CamlFp>>,
prev_challenges: Vec<CamlFp>,
prev_sgs: Vec<CamlGVesta>,
) -> Result<CamlProofWithPublic<CamlGVesta, CamlFp>, ocaml::Error> {
{
index
.as_ref()
.0
.srs
.with_lagrange_basis(index.as_ref().0.cs.domain.d1);
}
let prev = if prev_challenges.is_empty() {
Vec::new()
} else {
let challenges_per_sg = prev_challenges.len() / prev_sgs.len();
prev_sgs
.into_iter()
.map(Into::<Vesta>::into)
.enumerate()
.map(|(i, sg)| {
let chals = prev_challenges[(i * challenges_per_sg)..(i + 1) * challenges_per_sg]
.iter()
.map(Into::<Fp>::into)
.collect();
let comm = PolyComm::<Vesta> { chunks: vec![sg] };
RecursionChallenge { chals, comm }
})
.collect()
};
let witness: Vec<Vec<_>> = witness.iter().map(|x| (**x).clone()).collect();
let witness: [Vec<_>; COLUMNS] = witness
.try_into()
.map_err(|_| ocaml::Error::Message("the witness should be a column of 15 vectors"))?;
let index: &ProverIndex<Vesta, OpeningProof<Vesta>> = &index.as_ref().0;
let runtime_tables: Vec<RuntimeTable<Fp>> =
runtime_tables.into_iter().map(Into::into).collect();
let public_input = witness[0][0..index.cs.public].to_vec();
let runtime = unsafe { ocaml::Runtime::recover_handle() };
runtime.releasing_runtime(|| {
let group_map = GroupMap::<Fq>::setup();
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&runtime_tables,
index,
prev,
None,
&mut rand::rngs::OsRng,
)
.map_err(|e| ocaml::Error::Error(e.into()))?;
let verifier_index = index.verifier_index();
verify::<Vesta, EFqSponge, EFrSponge, OpeningProof<Vesta>>(
&group_map,
&verifier_index,
&proof,
&public_input,
)?;
Ok((proof, public_input).into())
})
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_example_with_lookup(
srs: CamlFpSrs,
) -> (
CamlPastaFpPlonkIndex,
CamlFp,
CamlProofWithPublic<CamlGVesta, CamlFp>,
) {
use ark_ff::Zero;
use kimchi::circuits::{
constraints::ConstraintSystem,
gate::{CircuitGate, GateType},
lookup::{
runtime_tables::{RuntimeTable, RuntimeTableCfg},
tables::LookupTable,
},
polynomial::COLUMNS,
wires::Wire,
};
use poly_commitment::ipa::endos;
let num_gates = 1000;
let num_tables: usize = 5;
let fixed_tables = vec![LookupTable {
id: 0,
data: vec![vec![0, 0, 0, 0, 0].into_iter().map(Into::into).collect()],
}];
let mut runtime_tables_setup = vec![];
let first_column: Vec<_> = [8u32, 9, 8, 7, 1].into_iter().map(Into::into).collect();
for table_id in 0..num_tables {
let cfg = RuntimeTableCfg {
id: table_id as i32,
first_column: first_column.clone(),
};
runtime_tables_setup.push(cfg);
}
let data: Vec<Fp> = [0u32, 2, 3, 4, 5].into_iter().map(Into::into).collect();
let runtime_tables: Vec<RuntimeTable<Fp>> = runtime_tables_setup
.iter()
.map(|cfg| RuntimeTable {
id: cfg.id(),
data: data.clone(),
})
.collect();
let mut gates = vec![];
for row in 0..num_gates {
gates.push(CircuitGate {
typ: GateType::Lookup,
wires: Wire::for_row(row),
coeffs: vec![],
});
}
let witness = {
let mut cols: [_; COLUMNS] = core::array::from_fn(|_col| vec![Fp::zero(); gates.len()]);
let (lookup_cols, _rest) = cols.split_at_mut(7);
for row in 0..num_gates {
lookup_cols[0][row] = ((row % num_tables) as u64).into();
let lookup_cols = &mut lookup_cols[1..];
for (chunk_id, chunk) in lookup_cols.chunks_mut(2).enumerate() {
if (row + chunk_id) % 2 == 0 {
chunk[0][row] = 9u32.into(); chunk[1][row] = 2u32.into(); } else {
chunk[0][row] = 8u32.into(); chunk[1][row] = 3u32.into(); }
}
}
cols
};
let num_public_inputs = 1;
let cs = ConstraintSystem::<Fp>::create(gates)
.runtime(Some(runtime_tables_setup))
.lookup(fixed_tables)
.public(num_public_inputs)
.build()
.unwrap();
srs.0.with_lagrange_basis(cs.domain.d1);
let (endo_q, _endo_r) = endos::<Pallas>();
let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
let group_map = <Vesta as CommitmentCurve>::Map::setup();
let public_input = witness[0][0];
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&runtime_tables,
&index,
vec![],
None,
&mut rand::rngs::OsRng,
)
.unwrap();
let caml_prover_proof = (proof, vec![public_input]).into();
(
CamlPastaFpPlonkIndex(Box::new(index)),
public_input.into(),
caml_prover_proof,
)
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_example_with_foreign_field_mul(
srs: CamlFpSrs,
) -> (
CamlPastaFpPlonkIndex,
CamlProofWithPublic<CamlGVesta, CamlFp>,
) {
use ark_ff::Zero;
use kimchi::circuits::{
constraints::ConstraintSystem,
gate::{CircuitGate, Connect},
polynomials::{foreign_field_common::BigUintForeignFieldHelpers, foreign_field_mul},
wires::Wire,
};
use num_bigint::{BigUint, RandBigInt};
use o1_utils::FieldHelpers;
use poly_commitment::ipa::endos;
use rand::{rngs::StdRng, SeedableRng};
let foreign_field_modulus = Fq::modulus_biguint();
let (mut next_row, mut gates) =
CircuitGate::<Fp>::create_foreign_field_mul(0, &foreign_field_modulus);
let rng = &mut StdRng::from_seed([2u8; 32]);
let left_input = rng.gen_biguint_range(&BigUint::zero(), &foreign_field_modulus);
let right_input = rng.gen_biguint_range(&BigUint::zero(), &foreign_field_modulus);
let (mut witness, mut external_checks) =
foreign_field_mul::witness::create(&left_input, &right_input, &foreign_field_modulus);
CircuitGate::extend_compact_multi_range_check(&mut gates, &mut next_row);
gates.connect_cell_pair((1, 0), (4, 1)); gates.connect_cell_pair((1, 1), (2, 0)); external_checks.extend_witness_compact_multi_range_checks(&mut witness);
CircuitGate::extend_high_bounds(&mut gates, &mut next_row, &foreign_field_modulus);
gates.connect_cell_pair((6, 0), (1, 1)); external_checks.extend_witness_high_bounds_computation(&mut witness, &foreign_field_modulus);
CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
gates.connect_cell_pair((1, 2), (7, 0)); gates.connect_cell_pair((1, 3), (8, 0)); gates.connect_cell_pair((1, 4), (9, 0)); CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
gates.connect_cell_pair((1, 5), (11, 0)); gates.connect_cell_pair((0, 6), (12, 0)); gates.connect_cell_pair((1, 6), (13, 0)); external_checks.extend_witness_multi_range_checks(&mut witness);
let left_limbs = left_input.to_field_limbs();
let right_limbs = right_input.to_field_limbs();
external_checks.add_high_bound_computation(&left_limbs[2]);
external_checks.add_high_bound_computation(&right_limbs[2]);
CircuitGate::extend_high_bounds(&mut gates, &mut next_row, &foreign_field_modulus);
gates.connect_cell_pair((15, 0), (0, 2)); gates.connect_cell_pair((15, 3), (0, 5)); external_checks.extend_witness_high_bounds_computation(&mut witness, &foreign_field_modulus);
external_checks.add_multi_range_check(&left_limbs);
CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
gates.connect_cell_pair((0, 0), (16, 0)); gates.connect_cell_pair((0, 1), (17, 0)); gates.connect_cell_pair((0, 2), (18, 0)); external_checks.add_multi_range_check(&right_limbs);
CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
gates.connect_cell_pair((0, 3), (20, 0)); gates.connect_cell_pair((0, 4), (21, 0)); gates.connect_cell_pair((0, 5), (22, 0)); external_checks.extend_witness_multi_range_checks(&mut witness);
CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
gates.connect_cell_pair((6, 2), (24, 0)); let left_hi_bound =
foreign_field_mul::witness::compute_bound(&left_input, &foreign_field_modulus);
let right_hi_bound =
foreign_field_mul::witness::compute_bound(&right_input, &foreign_field_modulus);
external_checks.add_limb_check(&left_hi_bound.into());
external_checks.add_limb_check(&right_hi_bound.into());
gates.connect_cell_pair((15, 2), (25, 0)); gates.connect_cell_pair((15, 5), (26, 0)); external_checks.extend_witness_limb_checks(&mut witness);
for _ in 0..(1 << 13) {
gates.push(CircuitGate::zero(Wire::for_row(next_row)));
next_row += 1;
}
let cs = ConstraintSystem::<Fp>::create(gates).build().unwrap();
srs.0.with_lagrange_basis(cs.domain.d1);
let (endo_q, _endo_r) = endos::<Pallas>();
let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
let group_map = <Vesta as CommitmentCurve>::Map::setup();
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&[],
&index,
vec![],
None,
&mut rand::rngs::OsRng,
)
.unwrap();
(
CamlPastaFpPlonkIndex(Box::new(index)),
(proof, vec![]).into(),
)
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_example_with_range_check(
srs: CamlFpSrs,
) -> (
CamlPastaFpPlonkIndex,
CamlProofWithPublic<CamlGVesta, CamlFp>,
) {
use ark_ff::Zero;
use kimchi::circuits::{
constraints::ConstraintSystem,
gate::CircuitGate,
polynomials::{foreign_field_common::BigUintForeignFieldHelpers, range_check},
wires::Wire,
};
use num_bigint::{BigUint, RandBigInt};
use o1_utils::BigUintFieldHelpers;
use poly_commitment::ipa::endos;
use rand::{rngs::StdRng, SeedableRng};
let rng = &mut StdRng::from_seed([255u8; 32]);
let (mut next_row, mut gates) = CircuitGate::<Fp>::create_multi_range_check(0);
let witness = range_check::witness::create_multi::<Fp>(
rng.gen_biguint_range(&BigUint::zero(), &BigUint::two_to_limb())
.to_field()
.expect("failed to convert to field"),
rng.gen_biguint_range(&BigUint::zero(), &BigUint::two_to_limb())
.to_field()
.expect("failed to convert to field"),
rng.gen_biguint_range(&BigUint::zero(), &BigUint::two_to_limb())
.to_field()
.expect("failed to convert to field"),
);
for _ in 0..(1 << 13) {
gates.push(CircuitGate::zero(Wire::for_row(next_row)));
next_row += 1;
}
let cs = ConstraintSystem::<Fp>::create(gates).build().unwrap();
srs.0.with_lagrange_basis(cs.domain.d1);
let (endo_q, _endo_r) = endos::<Pallas>();
let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
let group_map = <Vesta as CommitmentCurve>::Map::setup();
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&[],
&index,
vec![],
None,
&mut rand::rngs::OsRng,
)
.unwrap();
(
CamlPastaFpPlonkIndex(Box::new(index)),
(proof, vec![]).into(),
)
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_example_with_range_check0(
srs: CamlFpSrs,
) -> (
CamlPastaFpPlonkIndex,
CamlProofWithPublic<CamlGVesta, CamlFp>,
) {
use ark_ff::Zero;
use kimchi::circuits::{
constraints::ConstraintSystem,
gate::{CircuitGate, Connect},
polynomial::COLUMNS,
polynomials::{generic::GenericGateSpec, range_check},
wires::Wire,
};
use poly_commitment::ipa::endos;
let gates = {
let mut gates = vec![CircuitGate::<Fp>::create_generic_gadget(
Wire::for_row(0),
GenericGateSpec::Const(Fp::zero()),
None,
)];
let mut row = 1;
CircuitGate::<Fp>::extend_range_check(&mut gates, &mut row);
for _ in 0..(1 << 13) {
gates.push(CircuitGate::zero(Wire::for_row(gates.len())));
}
gates.connect_64bit(0, 1);
gates
};
let witness = {
let mut witness: [_; COLUMNS] = core::array::from_fn(|_col| vec![Fp::zero(); 1]);
range_check::witness::extend_single(&mut witness, Fp::from(2u128.pow(64) - 1));
witness
};
let cs = ConstraintSystem::<Fp>::create(gates).build().unwrap();
srs.0.with_lagrange_basis(cs.domain.d1);
let (endo_q, _endo_r) = endos::<Pallas>();
let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
let group_map = <Vesta as CommitmentCurve>::Map::setup();
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&[],
&index,
vec![],
None,
&mut rand::rngs::OsRng,
)
.unwrap();
(
CamlPastaFpPlonkIndex(Box::new(index)),
(proof, vec![]).into(),
)
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_example_with_ffadd(
srs: CamlFpSrs,
) -> (
CamlPastaFpPlonkIndex,
CamlFp,
CamlProofWithPublic<CamlGVesta, CamlFp>,
) {
use ark_ff::Zero;
use kimchi::circuits::{
constraints::ConstraintSystem,
gate::{CircuitGate, Connect},
polynomial::COLUMNS,
polynomials::{
foreign_field_add::witness::{create_chain, FFOps},
generic::GenericGateSpec,
range_check,
},
wires::Wire,
};
use num_bigint::BigUint;
use poly_commitment::ipa::endos;
let num_public_inputs = 1;
let operation = &[FFOps::Add];
let modulus = BigUint::from_bytes_be(&[
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF,
0xFC, 0x2F,
]);
let gates = {
let mut gates = vec![CircuitGate::<Fp>::create_generic_gadget(
Wire::for_row(0),
GenericGateSpec::Pub,
None,
)];
let mut curr_row = num_public_inputs;
CircuitGate::<Fp>::extend_chain_ffadd(&mut gates, 0, &mut curr_row, operation, &modulus);
for _ in 0..4 {
CircuitGate::extend_multi_range_check(&mut gates, &mut curr_row);
}
gates.connect_ffadd_range_checks(1, Some(4), Some(8), 12);
gates.connect_ffadd_range_checks(2, None, None, 16);
for _ in 0..(1 << 13) {
gates.push(CircuitGate::zero(Wire::for_row(curr_row)));
curr_row += 1;
}
gates
};
let witness = {
let mut witness: [_; COLUMNS] = core::array::from_fn(|_col| vec![Fp::zero(); 1]);
witness[0][0] = Fp::one();
let left = modulus.clone() - BigUint::from_bytes_be(&[1]);
let right = modulus.clone() - BigUint::from_bytes_be(&[1]);
let add_witness = create_chain::<Fp>(&[left, right], operation, modulus);
for col in 0..COLUMNS {
witness[col].extend(add_witness[col].iter());
}
let left = (witness[0][1], witness[1][1], witness[2][1]);
range_check::witness::extend_multi(&mut witness, left.0, left.1, left.2);
let right = (witness[3][1], witness[4][1], witness[5][1]);
range_check::witness::extend_multi(&mut witness, right.0, right.1, right.2);
let output = (witness[0][2], witness[1][2], witness[2][2]);
range_check::witness::extend_multi(&mut witness, output.0, output.1, output.2);
let bound = (witness[0][3], witness[1][3], witness[2][3]);
range_check::witness::extend_multi(&mut witness, bound.0, bound.1, bound.2);
witness
};
let cs = ConstraintSystem::<Fp>::create(gates)
.public(num_public_inputs)
.build()
.unwrap();
srs.0.with_lagrange_basis(cs.domain.d1);
let (endo_q, _endo_r) = endos::<Pallas>();
let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
let group_map = <Vesta as CommitmentCurve>::Map::setup();
let public_input = witness[0][0];
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&[],
&index,
vec![],
None,
&mut rand::rngs::OsRng,
)
.unwrap();
(
CamlPastaFpPlonkIndex(Box::new(index)),
public_input.into(),
(proof, vec![public_input]).into(),
)
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_example_with_xor(
srs: CamlFpSrs,
) -> (
CamlPastaFpPlonkIndex,
(CamlFp, CamlFp),
CamlProofWithPublic<CamlGVesta, CamlFp>,
) {
use ark_ff::Zero;
use kimchi::circuits::{
constraints::ConstraintSystem,
gate::{CircuitGate, Connect},
polynomial::COLUMNS,
polynomials::{generic::GenericGateSpec, xor},
wires::Wire,
};
use poly_commitment::ipa::endos;
let num_public_inputs = 2;
let gates = {
let mut gates = vec![];
for row in 0..num_public_inputs {
gates.push(CircuitGate::<Fp>::create_generic_gadget(
Wire::for_row(row),
GenericGateSpec::Pub,
None,
));
}
CircuitGate::<Fp>::extend_xor_gadget(&mut gates, 128);
gates.connect_cell_pair((0, 0), (2, 0));
gates.connect_cell_pair((1, 0), (2, 1));
for _ in 0..(1 << 13) {
gates.push(CircuitGate::zero(Wire::for_row(gates.len())));
}
gates
};
let witness = {
let mut cols: [_; COLUMNS] =
core::array::from_fn(|_col| vec![Fp::zero(); num_public_inputs]);
let input1 = 0xDC811727DAF22EC15927D6AA275F406Bu128;
let input2 = 0xA4F4417AF072DF9016A1EAB458DA80D1u128;
cols[0][0] = input1.into();
cols[0][1] = input2.into();
xor::extend_xor_witness::<Fp>(&mut cols, input1.into(), input2.into(), 128);
cols
};
let cs = ConstraintSystem::<Fp>::create(gates)
.public(num_public_inputs)
.build()
.unwrap();
srs.0.with_lagrange_basis(cs.domain.d1);
let (endo_q, _endo_r) = endos::<Pallas>();
let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
let group_map = <Vesta as CommitmentCurve>::Map::setup();
let public_input = (witness[0][0], witness[0][1]);
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&[],
&index,
vec![],
None,
&mut rand::rngs::OsRng,
)
.unwrap();
(
CamlPastaFpPlonkIndex(Box::new(index)),
(public_input.0.into(), public_input.1.into()),
(proof, vec![public_input.0, public_input.1]).into(),
)
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_example_with_rot(
srs: CamlFpSrs,
) -> (
CamlPastaFpPlonkIndex,
(CamlFp, CamlFp),
CamlProofWithPublic<CamlGVesta, CamlFp>,
) {
use ark_ff::Zero;
use kimchi::circuits::{
constraints::ConstraintSystem,
gate::{CircuitGate, Connect},
polynomial::COLUMNS,
polynomials::{
generic::GenericGateSpec,
rot::{self, RotMode},
},
wires::Wire,
};
use poly_commitment::ipa::endos;
let num_public_inputs = 2;
let rot = 32;
let mode = RotMode::Left;
let gates = {
let mut gates = vec![];
for row in 0..num_public_inputs {
gates.push(CircuitGate::<Fp>::create_generic_gadget(
Wire::for_row(row),
GenericGateSpec::Pub,
None,
));
}
CircuitGate::<Fp>::extend_rot(&mut gates, rot, mode, 1);
gates.connect_cell_pair((0, 0), (2, 0));
for _ in 0..(1 << 13) {
gates.push(CircuitGate::zero(Wire::for_row(gates.len())));
}
gates
};
let witness = {
let mut cols: [_; COLUMNS] = core::array::from_fn(|_col| vec![Fp::zero(); 2]);
let input = 0xDC811727DAF22EC1u64;
cols[0][0] = input.into();
rot::extend_rot::<Fp>(&mut cols, input, rot, mode);
cols
};
let cs = ConstraintSystem::<Fp>::create(gates)
.public(num_public_inputs)
.build()
.unwrap();
srs.0.with_lagrange_basis(cs.domain.d1);
let (endo_q, _endo_r) = endos::<Pallas>();
let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
let group_map = <Vesta as CommitmentCurve>::Map::setup();
let public_input = (witness[0][0], witness[0][1]);
let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
&group_map,
witness,
&[],
&index,
vec![],
None,
&mut rand::rngs::OsRng,
)
.unwrap();
(
CamlPastaFpPlonkIndex(Box::new(index)),
(public_input.0.into(), public_input.1.into()),
(proof, vec![public_input.0, public_input.1]).into(),
)
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_verify(
index: CamlPastaFpPlonkVerifierIndex,
proof: CamlProofWithPublic<CamlGVesta, CamlFp>,
) -> bool {
let group_map = <Vesta as CommitmentCurve>::Map::setup();
let (proof, public_input) = proof.into();
let verifier_index = index.into();
let context = Context {
verifier_index: &verifier_index,
proof: &proof,
public_input: &public_input,
};
batch_verify::<
Vesta,
DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>,
DefaultFrSponge<Fp, PlonkSpongeConstantsKimchi>,
OpeningProof<Vesta>,
>(&group_map, &[context])
.is_ok()
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_batch_verify(
indexes: Vec<CamlPastaFpPlonkVerifierIndex>,
proofs: Vec<CamlProofWithPublic<CamlGVesta, CamlFp>>,
) -> bool {
let ts: Vec<_> = indexes
.into_iter()
.zip(proofs.into_iter())
.map(|(caml_index, caml_proof)| {
let verifier_index: VerifierIndex<Vesta, OpeningProof<Vesta>> = caml_index.into();
let (proof, public_input): (ProverProof<Vesta, OpeningProof<Vesta>>, Vec<_>) =
caml_proof.into();
(verifier_index, proof, public_input)
})
.collect();
let ts_ref: Vec<Context<Vesta, OpeningProof<Vesta>>> = ts
.iter()
.map(|(verifier_index, proof, public_input)| Context {
verifier_index,
proof,
public_input,
})
.collect();
let group_map = GroupMap::<Fq>::setup();
batch_verify::<
Vesta,
DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>,
DefaultFrSponge<Fp, PlonkSpongeConstantsKimchi>,
OpeningProof<Vesta>,
>(&group_map, &ts_ref)
.is_ok()
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_dummy() -> CamlProofWithPublic<CamlGVesta, CamlFp> {
fn comm() -> PolyComm<Vesta> {
let g = Vesta::generator();
PolyComm {
chunks: vec![g, g, g],
}
}
let prev = RecursionChallenge {
chals: vec![Fp::one(), Fp::one()],
comm: comm(),
};
let prev_challenges = vec![prev.clone(), prev.clone(), prev];
let g = Vesta::generator();
let proof = OpeningProof {
lr: vec![(g, g), (g, g), (g, g)],
z1: Fp::one(),
z2: Fp::one(),
delta: g,
sg: g,
};
let eval = || PointEvaluations {
zeta: vec![Fp::one()],
zeta_omega: vec![Fp::one()],
};
let evals = ProofEvaluations {
public: Some(eval()),
w: core::array::from_fn(|_| eval()),
coefficients: core::array::from_fn(|_| eval()),
z: eval(),
s: core::array::from_fn(|_| eval()),
generic_selector: eval(),
poseidon_selector: eval(),
complete_add_selector: eval(),
mul_selector: eval(),
emul_selector: eval(),
endomul_scalar_selector: eval(),
range_check0_selector: None,
range_check1_selector: None,
foreign_field_add_selector: None,
foreign_field_mul_selector: None,
xor_selector: None,
rot_selector: None,
lookup_aggregation: None,
lookup_table: None,
lookup_sorted: array::from_fn(|_| None),
runtime_lookup_table: None,
runtime_lookup_table_selector: None,
xor_lookup_selector: None,
lookup_gate_lookup_selector: None,
range_check_lookup_selector: None,
foreign_field_mul_lookup_selector: None,
};
let public = vec![Fp::one(), Fp::one()];
let dlogproof = ProverProof {
commitments: ProverCommitments {
w_comm: core::array::from_fn(|_| comm()),
z_comm: comm(),
t_comm: comm(),
lookup: None,
},
proof,
evals,
ft_eval1: Fp::one(),
prev_challenges,
};
(dlogproof, public).into()
}
#[ocaml_gen::func]
#[ocaml::func]
pub fn caml_pasta_fp_plonk_proof_deep_copy(
x: CamlProofWithPublic<CamlGVesta, CamlFp>,
) -> CamlProofWithPublic<CamlGVesta, CamlFp> {
x
}