Skip to content

[kimchi][doc] update readme example with circuit-construction API #555

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 13, 2022
133 changes: 92 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,104 @@ You can read more about this project on the [Kimchi book](https://o1-labs.github

## Example

We assume that you already have:

* `gates`: a circuit, which can be expressed as a vector of [CircuitGate](https://o1-labs.github.io/proof-systems/rustdoc/kimchi/circuits/gate/struct.CircuitGate.html)
* a way to produce a `witness`, which can be expressed as a `[Vec<F>; COLUMNS]` (for `F` some field of your chosing)
* `public_size`: the size of the public input

Then, you can create an URS for your circuit in the following way:

```rust,ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the description above the example could be updated

Copy link
Contributor Author

@katat katat Jun 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to outline the workflow and try to explain the code with a bit more comments. Please have a check.

Note I still use the name circuit-construction and the name kimchi still remains. I guess they can remain until a new name for circuit-construction is determined.

use kimchi::{circuits::constraints, verifier::verify};
use mina_curves::pasta::{fp::Fp, vesta::{Affine, VestaParameters}, pallas::Affine as Other};
use oracle::{
constants::PlonkSpongeConstantsKimchi,
sponge::{DefaultFqSponge, DefaultFrSponge},
The following is an example to demonstrate a full cycle workflow using circuit-construction:

1. Specify a circuit
2. Create SRS
3. Generate prover index
4. Generate a proof
5. Verify the proof

```rust
use std::sync::Arc;
use ark_ff::{FftField, PrimeField};
use ark_poly::{EvaluationDomain, Radix2EvaluationDomain};
use circuit_construction::{
*,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid importing *, unless it's a well-defined module (like prologue) that is meant to be opened in the root scope

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is an attempt to use a prologue. It does simplify the import a lot, just use one line. But I am not sure if there are any potential issues when it comes to practice :D

katat#1

oracle::{
constants::*,
poseidon::{Sponge},
sponge::{DefaultFqSponge, DefaultFrSponge},
},
kimchi::verifier::verify,
commitment_dlog::{commitment::CommitmentCurve, srs::SRS},
groupmap::GroupMap,
mina_curves::pasta::{
fp::Fp,
vesta::{Affine, VestaParameters},
}
};
use commitment_dlog::commitment::{b_poly_coefficients, ceil_log2, CommitmentCurve};

type SpongeParams = PlonkSpongeConstantsKimchi;
type BaseSponge = DefaultFqSponge<VestaParameters, SpongeParams>;
type ScalarSponge = DefaultFrSponge<Fp, SpongeParams>;

// compile the circuit
let fp_sponge_params = oracle::pasta::fp_kimchi::params();
let cs = ConstraintSystem::<Fp>::create(gates, vec![], fp_sponge_params, public_size).unwrap();

// create an URS
let mut urs = SRS::<Affine>::create(cs.domain.d1.size as usize);
srs.add_lagrange_basis(cs.domain.d1);

// obtain a prover index
let prover_index = {
let fq_sponge_params = oracle::pasta::fq_kimchi::params();
let (endo_q, _endo_r) = endos::<Other>();
Index::<Affine>::create(cs, fq_sponge_params, endo_q, srs)
type SpongeQ = DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>;
type SpongeR = DefaultFrSponge<Fp, PlonkSpongeConstantsKimchi>;

// a callback function to specify constraint gates for a circuit
pub fn circuit<
F: PrimeField + FftField,
Sys: Cs<F>,
>(
witness: Option<F>,
sys: &mut Sys,
public_input: Vec<Var<F>>,
) {
// add a constant gate
let three = sys.constant(3u32.into());
// read the first public input
let first_public_input = public_input[0];
// create a free variable to hold a witness value
let witness = sys.var(|| witness.unwrap());

// create a free variable to hold a calculation result
let result = sys.var(|| {
first_public_input.val() + witness.val()
});

// add a gate to assert the calculation equals to a constant constraint
sys.assert_eq(result, three);
}

// create SRS
let srs = {
let mut srs = SRS::<Affine>::create(1 << 3); // 2^3 = 8
srs.add_lagrange_basis(Radix2EvaluationDomain::new(srs.g.len()).unwrap());
Arc::new(srs)
};

// obtain a verifier index
let verifier_index = prover_index.verifier_index();

// create a proof
let public_inputs = vec![1i32.into()];
let group_map = <Affine as CommitmentCurve>::Map::setup();
let proof = ProverProof::create::<BaseSponge, ScalarSponge>(
&group_map, witness, &prover_index);

// verify a proof
verify::<Affine, BaseSponge, ScalarSponge>(&group_map, verifier_index, proof).unwrap();
// generate circuit and index
let prover_index = generate_prover_index::<FpInner, _>(
srs,
&fp_constants(),
&oracle::pasta::fq_kimchi::params(),
// to determine how many placeholders to generate for public inputs
public_inputs.len(),
// use the circuit callback to generate gate constraints
// with placeholders for the witness and public inputs
|sys, p| circuit::<_, _>(None, sys, p),
);

// create witness
let witness = 2i32;

// generate proof
let proof = prove::<Affine, _, SpongeQ, SpongeR>(
&prover_index,
&group_map,
None,
public_inputs,
// use the same circuit callbacb
// but with values for witness and public inputs
|sys, p| circuit::<Fp, _>(Some(witness.into()), sys, p),
);

// verify proof
let verifier_index = prover_index.verifier_index();
verify::<_, SpongeQ, SpongeR>(&group_map, &verifier_index, &proof).unwrap();
```

For the other examples, please refer to the [tests](./circuit-construction/tests/).

Note that kimchi is specifically designed for use in a recursion proof system, like [pickles](https://medium.com/minaprotocol/meet-pickles-snark-enabling-smart-contract-on-coda-protocol-7ede3b54c250), but can also be used a stand alone for normal proofs.

## Organization
Expand All @@ -71,6 +121,7 @@ The project is organized in the following way:
* [groupmap/](https://github.com/o1-labs/proof-systems/tree/master/groupmap). Used to convert elliptic curve elements to field elements.
* [hasher/](https://github.com/o1-labs/proof-systems/tree/master/hasher). Interfaces for mina hashing.
* [kimchi/](https://github.com/o1-labs/proof-systems/tree/master/kimchi). Our proof system.
* [circuit-construction/](https://github.com/o1-labs/proof-systems/tree/master/circuit-construction). Circuit writer.
* [ocaml/](https://github.com/o1-labs/proof-systems/tree/master/ocaml). Ocaml bindings generator tool.
* [oracle/](https://github.com/o1-labs/proof-systems/tree/master/oracle). Implementation of the poseidon hash function.
* [poly-commitment/](https://github.com/o1-labs/proof-systems/tree/master/poly-commitment). Polynomial commitment code.
Expand Down
8 changes: 8 additions & 0 deletions circuit-construction/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
#![doc = include_str!("../../README.md")]

pub use commitment_dlog;
pub use groupmap;
pub use kimchi;
pub use mina_curves;
pub use oracle;

use ark_ec::{AffineCurve, ProjectiveCurve};
use ark_ff::{BigInteger, FftField, Field, One, PrimeField, SquareRootField, Zero};
use array_init::array_init;
Expand Down
28 changes: 15 additions & 13 deletions circuit-construction/tests/example_proof.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
use ark_ec::{AffineCurve, ProjectiveCurve};
use ark_ff::{FftField, PrimeField, UniformRand};
use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as D};
use circuit_construction::*;
use commitment_dlog::{commitment::CommitmentCurve, srs::SRS};
use groupmap::GroupMap;
use kimchi::verifier::verify;
use mina_curves::pasta::{
fp::Fp,
pallas::Affine as Other,
vesta::{Affine, VestaParameters},
};
use oracle::{
constants::*,
poseidon::{ArithmeticSponge, Sponge},
sponge::{DefaultFqSponge, DefaultFrSponge},
use circuit_construction::{
commitment_dlog::{commitment::CommitmentCurve, srs::SRS},
groupmap::GroupMap,
kimchi::verifier::verify,
mina_curves::pasta::{
fp::Fp,
pallas::Affine as Other,
vesta::{Affine, VestaParameters},
},
oracle::{
constants::*,
poseidon::{ArithmeticSponge, Sponge},
sponge::{DefaultFqSponge, DefaultFrSponge},
},
*,
};
use std::sync::Arc;

Expand Down
2 changes: 1 addition & 1 deletion kimchi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![doc = include_str!("../../README.md")]
#![doc = include_str!("../README.md")]

#[macro_use]
extern crate num_derive;
Expand Down