Skip to content
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

shuffle API support #72

Merged
merged 3 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ build
vk_deployment/

.aptos/
.vscode/
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
## halo2 verifier in Move
# halo2 verifier in Move

The project is a halo2 verifier written in Move language.
The project is a halo2 verifier written in Move language.
Its objective to enhance the capability of the blockchains in the Move ecosystem by enabling halo2 zero-knowledge proofs to be verified on-chain.

### Why the project
## Why the project

Halo2 is a widely used plonk implementation. zcash, scroll, axiom, taiko and many other famous projects are developed based on halo2.
There exists a general verification process for different circuits in rust,
however, blockchains cannot utilize the code directly because of the gap in the language or api.
several organizations are developing onchain verifiers(like [halo-solidity-verifier](https://github.com/privacy-scaling-explorations/halo2-solidity-verifier)) in solidity for EVM communities,
although it’s not a general verifier code, only a general template generator.
There exists a general verification process for different circuits in rust,
however, blockchains cannot utilize the code directly because of the gap in the language or api.
several organizations are developing onchain verifiers(like [halo-solidity-verifier](https://github.com/privacy-scaling-explorations/halo2-solidity-verifier)) in solidity for EVM communities,
although it’s not a general verifier code, only a general template generator.
One still needs to generate a verifier contract for each circuit sharing most of the code.

halo2-verifier.move uses a different approach, it tries to extract the information of a halo2 circuit, and abstract them out into a `Protocol` of the circuit(we call it the shape of a circuit), circuit’s shape includes:
Expand All @@ -22,6 +22,6 @@ halo2-verifier.move uses a different approach, it tries to extract the informati

With these information, the general verifier can read commitments and evaluations in proofs of the circuit, and do verification accordingly using a polynomial commitment scheme.

### Give it a try
## Give it a try

See [TUTORIAL.md](./TUTORIAL.md).
17 changes: 11 additions & 6 deletions TUTORIAL.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
### Tutorial on halo2-verifier
# Tutorial on halo2-verifier

This doc will guide you through the usage of halo2-verifier.

Cli `aptos` is necessary for the tutorial, make sure you download it from https://github.com/aptos-labs/aptos-core/releases.
Cli `aptos` is necessary for the tutorial, make sure you download it from <https://github.com/aptos-labs/aptos-core/releases>.
Also, the repo is an essence.


First, let's create an aptos profile on aptos devnet.
Execute the command under the project root. It will generate config file of aptos account in `.aptos/config.yaml`.

Expand All @@ -16,6 +15,7 @@ aptos init --network devnet
Next, we need to publish the halo2-verifier & halo2-common modules to aptos devnet under the new-generated profile account.
The following commands will use aptos cli to compile and publish the three packages: `common`, `verifier` and `api`.
When first executing, it will fetch dependencies, which may need a little time. so be patient here.

``` shell
cd packages/common
aptos move publish --skip-fetch-latest-git-deps --named-addresses halo2_common=default
Expand All @@ -31,32 +31,37 @@ But first, we need a params of kzg setup. There exists a setup called [Perpetual
We're going to use a version of axiom.
the existing param file `crates/vk-gen-examples/params/challenge_0078-kzg_bn254_16.srs` is downloaded from [axiom page](https://docs.axiom.xyz/transparency-and-security/kzg-trusted-setup).

To view the kzg setup params, run the following cargo commands under directory `crates/vk-gen-examples`.
To view the kzg setup params, run the following cargo commands under directory `crates/vk-gen-examples`.
It will output the g1, g2, and s_g2.

```shell
cargo run --release -- --param-path params/challenge_0078-kzg_bn254_16.srs view-param
```

We have to send a create-params transcation to make the params available on aptos.
Copy paste the `g1`, `g2`, `s_g2` as aptos args, resulting the following aptos command:
Copy paste the `g1`, `g2`, `s_g2` as aptos args, resulting the following aptos command:

```shell
aptos move run --function-id default::param_store::create --args hex:0x0100000000000000000000000000000000000000000000000000000000000000 hex:0xedf692d95cbdde46ddda5ef7d422436779445c5e66006a42761e1f12efde0018c212f3aeb785e49712e7a9353349aaf1255dfb31b7bf60723a480d9293938e19 hex:e4115200acc86e7670c83ded726335def098657fe8668323e9e41e6781b83b0a9d83b54bbb00215323ce6d7f9d7f331a286d7707d03f7dbdd3125c6163588d13
```

Then, we are ready to publish a circuit!
We're going to use example `vector-mul` in our vk-gen-examples.
Enter directory `crates/vk-gen-examples`, and run the cargo command, remember **replace the verifier-address with your aptos profile's address!**

```shell
cargo run --release -- --param-path params/challenge_0078-kzg_bn254_16.srs --verifier-address c9666cf9a032e81737eb706ce538a423706d86a2a502027fbc909e0817bf313b build-publish-vk-aptos-txn --example vector-mul
```

It will output a json file which you can take as input to `aptos move run`.

```shell
aptos move run --json-file VectorMul-publish-circuit.json
```

Now, the circuit is published. We'll build a verify proof aptos txn and run it on aptos.
Now, the circuit is published. We'll build a verify proof aptos txn and run it on aptos.
Run the command and replace the `verifier-address`/`param-address`/`circuit-address` with your aptos profile's address!

```shell
cargo run --release -- --param-path params/challenge_0078-kzg_bn254_16.srs --verifier-address c9666cf9a032e81737eb706ce538a423706d86a2a502027fbc909e0817bf313b build-verify-proof-aptos-txn --example vector-mul --kzg gwc --param-address c9666cf9a032e81737eb706ce538a423706d86a2a502027fbc909e0817bf313b --circuit-address c9666cf9a032e81737eb706ce538a423706d86a2a502027fbc909e0817bf313b
```
Expand Down
21 changes: 17 additions & 4 deletions crates/verifier-sdk/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/verifier-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ rand_core = { version = "0.6" }
serde = { version = "1" }
serde_json = { version = "1" }
hex = { version = "0.4.3" }
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" }
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v0.3.0" }
bcs = { version = "0.1.6" }
blake2b_simd = { version = "1" }



multipoly = {path = "./multipoly" }
shape-generator={path="./shape-generator"}
shape-generator={path="./shape-generator"}
19 changes: 10 additions & 9 deletions crates/verifier-sdk/aptos-verifier-api/src/proving.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use halo2_proofs::halo2curves::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
use halo2_proofs::arithmetic::CurveAffine;
use halo2_proofs::halo2curves::CurveExt;
use halo2_proofs::halo2curves::ff::{FromUniformBytes, WithSmallOrderMulGroup};
use halo2_proofs::halo2curves::pairing::{Engine, MultiMillerLoop};
use halo2_proofs::halo2curves::serde::SerdeObject;
use halo2_proofs::plonk::{create_proof, verify_proof, Circuit, ProvingKey};
Expand All @@ -16,19 +18,18 @@ use rand_core::OsRng;

pub fn prove_with_gwc_and_keccak256<E, ConcreteCircuit>(
circuit: ConcreteCircuit,
instance: &[&[E::Scalar]],
instance: &[&[E::Fr]],
params: &ParamsKZG<E>,
pk: ProvingKey<E::G1Affine>,
) -> Vec<u8>
where
E: Engine + Debug + MultiMillerLoop,
E::G1Affine: SerdeObject,
E::G2Affine: SerdeObject,
ConcreteCircuit: Circuit<E::Scalar>,
<E as Engine>::Scalar: PrimeField,
<E as Engine>::Scalar: Ord,
<E as Engine>::Scalar: WithSmallOrderMulGroup<3>,
<E as Engine>::Scalar: FromUniformBytes<64>,
E::G1Affine:
SerdeObject + CurveAffine<ScalarExt = <E as Engine>::Fr, CurveExt = <E as Engine>::G1>,
E::G1: CurveExt<AffineExt = E::G1Affine>,
E::G2Affine: SerdeObject + CurveAffine,
ConcreteCircuit: Circuit<E::Fr>,
<E as Engine>::Fr: Ord + WithSmallOrderMulGroup<3> + FromUniformBytes<64>,
{
prove_vm_circuit::<
KZGCommitmentScheme<E>,
Expand Down
40 changes: 40 additions & 0 deletions crates/verifier-sdk/shape-generator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct CircuitInfo<C: CurveAffine> {
fixed_queries: Vec<ColumnQuery>,
permutation_columns: Vec<Column>,
lookups: Vec<Lookup<C::Scalar>>,
shuffles: Vec<Shuffle<C::Scalar>>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -86,6 +87,11 @@ pub struct Lookup<F: Field> {
pub input_exprs: Vec<MultiVariatePolynomial<F>>,
pub table_exprs: Vec<MultiVariatePolynomial<F>>,
}
#[derive(Debug)]
pub struct Shuffle<F: Field> {
pub input_exprs: Vec<MultiVariatePolynomial<F>>,
pub shuffle_exprs: Vec<MultiVariatePolynomial<F>>,
}

pub type MultiVariatePolynomial<F> = SparsePolynomial<F, SparseTerm>;

Expand Down Expand Up @@ -194,6 +200,40 @@ where
.collect(),
})
.collect(),
shuffles: cs
.shuffles()
.iter()
.map(|s| Shuffle {
input_exprs: s
.input_expressions()
.iter()
.map(|e| {
expression_transform(
cs,
e,
cs.advice_queries().len(),
cs.fixed_queries().len(),
cs.instance_queries().len(),
cs.challenge_phase().len(),
)
})
.collect(),
shuffle_exprs: s
.shuffle_expressions()
.iter()
.map(|e| {
expression_transform(
cs,
e,
cs.advice_queries().len(),
cs.fixed_queries().len(),
cs.instance_queries().len(),
cs.challenge_phase().len(),
)
})
.collect(),
})
.collect(),
max_num_query_of_advice_column: cs
.advice_queries()
.iter()
Expand Down
55 changes: 55 additions & 0 deletions crates/verifier-sdk/shape-generator/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub struct SerializableCircuitInfo<C: CurveAffine> {
gates: Vec<IndexedMultiVariatePolynomial>,
lookups_input_exprs: Vec<Vec<IndexedMultiVariatePolynomial>>,
lookups_table_exprs: Vec<Vec<IndexedMultiVariatePolynomial>>,
shuffles_input_exprs: Vec<Vec<IndexedMultiVariatePolynomial>>,
shuffles_exprs: Vec<Vec<IndexedMultiVariatePolynomial>>,
}

type IndexedMultiVariatePolynomial = Vec<(u16, SparseTerm)>;
Expand Down Expand Up @@ -55,6 +57,7 @@ impl<C: CurveAffine> From<CircuitInfo<C>> for SerializableCircuitInfo<C> {
fixed_queries,
permutation_columns,
lookups,
shuffles,
}: CircuitInfo<C>,
) -> Self {
let mut fields_pool: Vec<C::Scalar> = Vec::new();
Expand Down Expand Up @@ -109,6 +112,44 @@ impl<C: CurveAffine> From<CircuitInfo<C>> for SerializableCircuitInfo<C> {
(inputs, tables)
},
);
let shuffles_len = shuffles.len();
let (shuffles_input, shuffles_shuffle) = shuffles.into_iter().fold(
(
Vec::with_capacity(shuffles_len),
Vec::with_capacity(shuffles_len),
),
|(mut shuffle_inputs, mut shuffles), s| {
shuffle_inputs.push(
s.input_exprs
.into_iter()
.map(|expr| {
expr.terms
.iter()
.map(|(coff, t)| {
let new_coff = index_element(&mut fields_pool, *coff);
(new_coff as u16, t.clone())
})
.collect::<Vec<_>>()
})
.collect(),
);
shuffles.push(
s.shuffle_exprs
.into_iter()
.map(|expr| {
expr.terms
.iter()
.map(|(coff, t)| {
let new_coff = index_element(&mut fields_pool, *coff);
(new_coff as u16, t.clone())
})
.collect::<Vec<_>>()
})
.collect(),
);
(shuffle_inputs, shuffles)
},
);

Self {
k,
Expand All @@ -127,6 +168,8 @@ impl<C: CurveAffine> From<CircuitInfo<C>> for SerializableCircuitInfo<C> {
gates,
lookups_input_exprs: inputs,
lookups_table_exprs: tables,
shuffles_input_exprs: shuffles_input,
shuffles_exprs: shuffles_shuffle,
fields_pool,
vk_transcript_repr,
fixed_commitments,
Expand Down Expand Up @@ -205,6 +248,16 @@ pub fn serialize<C: CurveAffine>(
.iter()
.map(serialize_lookup_exprs)
.collect();
let shuffles_input_exprs = circuit_info
.shuffles_input_exprs
.iter()
.map(serialize_lookup_exprs)
.collect();
let shuffles_shuffle_exprs = circuit_info
.shuffles_exprs
.iter()
.map(serialize_lookup_exprs)
.collect();
Ok(vec![
general_info,
advice_queries,
Expand All @@ -215,6 +268,8 @@ pub fn serialize<C: CurveAffine>(
gates,
lookups_input_exprs,
lookups_table_exprs,
shuffles_input_exprs,
shuffles_shuffle_exprs,
])
}

Expand Down
Loading