Skip to content

Commit

Permalink
Merge pull request #2477 from dusk-network/groth16
Browse files Browse the repository at this point in the history
rusk-abi: add `verify_groth16` host function
  • Loading branch information
Eduardo Leegwater Simões authored Sep 25, 2024
2 parents 7ea212c + bf7c282 commit 1c1137b
Show file tree
Hide file tree
Showing 14 changed files with 288 additions and 38 deletions.
24 changes: 20 additions & 4 deletions contracts/host_fn/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,22 @@ impl HostFnTest {
rusk_abi::poseidon_hash(scalars)
}

pub fn verify_proof(
pub fn verify_plonk(
&self,
verifier_data: Vec<u8>,
proof: Vec<u8>,
public_inputs: Vec<BlsScalar>,
) -> bool {
rusk_abi::verify_proof(verifier_data, proof, public_inputs)
rusk_abi::verify_plonk(verifier_data, proof, public_inputs)
}

pub fn verify_groth16_bn254(
&self,
pvk: Vec<u8>,
proof: Vec<u8>,
inputs: Vec<u8>,
) -> bool {
rusk_abi::verify_groth16_bn254(pvk, proof, inputs)
}

pub fn verify_schnorr(
Expand Down Expand Up @@ -91,9 +100,16 @@ unsafe fn poseidon_hash(arg_len: u32) -> u32 {
}

#[no_mangle]
unsafe fn verify_proof(arg_len: u32) -> u32 {
unsafe fn verify_plonk(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |(verifier_data, proof, public_inputs)| {
STATE.verify_proof(verifier_data, proof, public_inputs)
STATE.verify_plonk(verifier_data, proof, public_inputs)
})
}

#[no_mangle]
unsafe fn verify_groth16_bn254(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |(pvk, proof, inputs)| {
STATE.verify_groth16_bn254(pvk, proof, inputs)
})
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/license/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl LicenseContractState {
proof: Vec<u8>,
public_inputs: Vec<BlsScalar>,
) -> Result<(), Error> {
rusk_abi::verify_proof(verifier_data.to_vec(), proof, public_inputs)
rusk_abi::verify_plonk(verifier_data.to_vec(), proof, public_inputs)
.then_some(())
.ok_or(Error::ProofVerification)
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/transfer/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ fn verify_tx_proof(tx: &PhoenixTransaction) -> bool {
.to_vec();

// verify the proof
rusk_abi::verify_proof(vd, tx.proof().to_vec(), tx.public_inputs())
rusk_abi::verify_plonk(vd, tx.proof().to_vec(), tx.public_inputs())
}

#[cfg(test)]
Expand Down
4 changes: 4 additions & 0 deletions execution-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added `groth16` module allowing for proof generation and verification

## [0.1.0] - 2024-09-10

### Added
Expand Down
30 changes: 26 additions & 4 deletions execution-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,41 @@ rand = { version = "0.8", default-features = false }
ff = { version = "0.13", default-features = false }

# zk-dependencies

ark-groth16 = { version = "0.4", default-features = false, features = [], optional = true }
ark-bn254 = { version = "0.4", default-features = false, features = ["curve"], optional = true }
ark-relations = { version = "0.4", default-features = false, features = [], optional = true }
ark-serialize = { version = "0.4", default-features = false, features = [], optional = true }

dusk-plonk = { version = "0.20", default-features = false, features = ["rkyv-impl", "alloc"], optional = true }

[dev-dependencies]
rand = "0.8"

[features]
# It enables parallel thread aggregation of BlsPublicKey
parallel = ["bls12_381-bls/parallel"]
parallel = [
# It enables parallel thread aggregation of BlsPublicKey
"bls12_381-bls/parallel",
# It enables parallel feature for ark-groth16
"ark-groth16/parallel"
]

# It enables zk-capabilities
# Enables all zero-knowledge proof system libraries supported
zk = [
"plonk",
"groth16",
]

plonk = [
"dusk-plonk",
"phoenix-circuits/plonk"
"phoenix-circuits/plonk",
]

groth16 = [
"ark-groth16",
"ark-bn254",
"ark-relations",
"ark-serialize",
]

# Enables std feature for dusk-plonk
Expand Down
15 changes: 14 additions & 1 deletion execution-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,27 @@ pub use piecrust_uplink::{

/// Types and traits to create plonk circuits and generate and verify plonk
/// proofs.
#[cfg(feature = "zk")]
#[cfg(feature = "plonk")]
pub mod plonk {
pub use dusk_plonk::prelude::{
Circuit, Compiler, Composer, Constraint, Error, Proof, Prover,
PublicParameters, Verifier, Witness, WitnessPoint,
};
}

/// Groth16 circuitry
#[cfg(feature = "groth16")]
pub mod groth16 {
pub use ark_bn254 as bn254;
pub use ark_groth16::{
data_structures, generator, prepare_verifying_key, prover, r1cs_to_qap,
verifier, Groth16, PreparedVerifyingKey, Proof, ProvingKey,
VerifyingKey,
};
pub use ark_relations as relations;
pub use ark_serialize as serialize;
}

#[inline]
const fn reserved(b: u8) -> ContractId {
let mut bytes = [0u8; CONTRACT_ID_BYTES];
Expand Down
2 changes: 2 additions & 0 deletions rusk-abi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add the `verify_groth16_bn254` host function
- Memoize the `verify_bls` function
- Memoize the `verify_proof` function [#1228]
- New ABIs: `owner_raw`, `self_owner_raw` [#1710]

### Changed

- Rename `verify_proof` to `verify_plonk`
- Update `piecrust` to `0.22`
- Update `piecrust-uplink` to `0.15`
- Change dependencies declarations enforce bytecheck [#1371]
Expand Down
7 changes: 4 additions & 3 deletions rusk-abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ rkyv = { version = "=0.7.39", default-features = false, features = ["size_32"] }
lru = { version = "0.12", optional = true }

[dev-dependencies]
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
rand = "0.8"
once_cell = "1.15"
ff = { version = "0.13", default-features = false }
ff = "0.13"
hex = "0.4"

[features]
# By default, we include the contract writing features.
Expand All @@ -42,7 +43,7 @@ dlmalloc = ["piecrust-uplink/dlmalloc"]

# These are the features available for when one wishes to use `rusk-abi` as a
# host.
host = ["piecrust", "lru"]
host = ["piecrust", "lru", "execution-core/parallel"]
host_debug = ["piecrust/debug", "lru"]

[[test]]
Expand Down
18 changes: 15 additions & 3 deletions rusk-abi/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,25 @@ pub fn poseidon_hash(scalars: Vec<BlsScalar>) -> BlsScalar {
host_query(Query::POSEIDON_HASH, scalars)
}

/// Verify a proof is valid for a given circuit type and public inputs
pub fn verify_proof(
/// Verify that a Groth16 proof in the BN254 pairing is valid for a given
/// circuit and inputs.
///
/// `proof` and `inputs` should be in compressed form, while `pvk` uncompressed.
pub fn verify_groth16_bn254(
pvk: Vec<u8>,
proof: Vec<u8>,
inputs: Vec<u8>,
) -> bool {
host_query(Query::VERIFY_GROTH16_BN254, (pvk, proof, inputs))
}

/// Verify a Plonk proof is valid for a given circuit type and public inputs
pub fn verify_plonk(
verifier_data: Vec<u8>,
proof: Vec<u8>,
public_inputs: Vec<BlsScalar>,
) -> bool {
host_query(Query::VERIFY_PROOF, (verifier_data, proof, public_inputs))
host_query(Query::VERIFY_PLONK, (verifier_data, proof, public_inputs))
}

/// Verify a schnorr signature is valid for the given public key and message
Expand Down
60 changes: 52 additions & 8 deletions rusk-abi/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ use std::path::{Path, PathBuf};
use dusk_bytes::DeserializableSlice;
use dusk_poseidon::{Domain, Hash as PoseidonHash};
use execution_core::{
plonk::{Proof, Verifier},
groth16::{
bn254::{Bn254, G1Projective},
serialize::CanonicalDeserialize,
Groth16, PreparedVerifyingKey, Proof as Groth16Proof,
},
plonk::{Proof as PlonkProof, Verifier},
signatures::{
bls::{
MultisigPublicKey, MultisigSignature, PublicKey as BlsPublicKey,
Expand Down Expand Up @@ -78,7 +83,11 @@ pub fn new_ephemeral_vm() -> Result<VM, PiecrustError> {
fn register_host_queries(vm: &mut VM) {
vm.register_host_query(Query::HASH, host_hash);
vm.register_host_query(Query::POSEIDON_HASH, host_poseidon_hash);
vm.register_host_query(Query::VERIFY_PROOF, host_verify_proof);
vm.register_host_query(Query::VERIFY_PLONK, host_verify_plonk);
vm.register_host_query(
Query::VERIFY_GROTH16_BN254,
host_verify_groth16_bn254,
);
vm.register_host_query(Query::VERIFY_SCHNORR, host_verify_schnorr);
vm.register_host_query(Query::VERIFY_BLS, host_verify_bls);
vm.register_host_query(
Expand Down Expand Up @@ -114,17 +123,29 @@ fn host_poseidon_hash(arg_buf: &mut [u8], arg_len: u32) -> u32 {
wrap_host_query(arg_buf, arg_len, poseidon_hash)
}

fn host_verify_proof(arg_buf: &mut [u8], arg_len: u32) -> u32 {
fn host_verify_plonk(arg_buf: &mut [u8], arg_len: u32) -> u32 {
let hash = *blake2b_simd::blake2b(&arg_buf[..arg_len as usize]).as_array();
let cached = cache::get_plonk_verification(hash);

wrap_host_query(arg_buf, arg_len, |(vd, proof, pis)| {
let is_valid = cached.unwrap_or_else(|| verify_proof(vd, proof, pis));
let is_valid = cached.unwrap_or_else(|| verify_plonk(vd, proof, pis));
cache::put_plonk_verification(hash, is_valid);
is_valid
})
}

fn host_verify_groth16_bn254(arg_buf: &mut [u8], arg_len: u32) -> u32 {
let hash = *blake2b_simd::blake2b(&arg_buf[..arg_len as usize]).as_array();
let cached = cache::get_groth16_verification(hash);

wrap_host_query(arg_buf, arg_len, |(pvk, proof, inputs)| {
let is_valid =
cached.unwrap_or_else(|| verify_groth16_bn254(pvk, proof, inputs));
cache::put_groth16_verification(hash, is_valid);
is_valid
})
}

fn host_verify_schnorr(arg_buf: &mut [u8], arg_len: u32) -> u32 {
wrap_host_query(arg_buf, arg_len, |(msg, pk, sig)| {
verify_schnorr(msg, pk, sig)
Expand Down Expand Up @@ -160,22 +181,45 @@ pub fn poseidon_hash(scalars: Vec<BlsScalar>) -> BlsScalar {
PoseidonHash::digest(Domain::Other, &scalars)[0]
}

/// Verify a proof is valid for a given circuit type and public inputs
/// Verify a Plonk proof is valid for a given circuit type and public inputs
///
/// # Panics
/// This will panic if `verifier_data` is not valid.
pub fn verify_proof(
/// This will panic if `verifier_data` or `proof` are not valid.
pub fn verify_plonk(
verifier_data: Vec<u8>,
proof: Vec<u8>,
public_inputs: Vec<BlsScalar>,
) -> bool {
let verifier = Verifier::try_from_bytes(verifier_data)
.expect("Verifier data coming from the contract should be valid");
let proof = Proof::from_slice(&proof).expect("Proof should be valid");
let proof = PlonkProof::from_slice(&proof).expect("Proof should be valid");

verifier.verify(&proof, &public_inputs[..]).is_ok()
}

/// Verify that a Groth16 proof in the BN254 pairing is valid for a given
/// circuit and inputs.
///
/// `proof` and `inputs` should be in compressed form, while `pvk` uncompressed.
///
/// # Panics
/// This will panic if `pvk`, `proof` or `inputs` are not valid.
pub fn verify_groth16_bn254(
pvk: Vec<u8>,
proof: Vec<u8>,
inputs: Vec<u8>,
) -> bool {
let pvk = PreparedVerifyingKey::deserialize_uncompressed(&pvk[..])
.expect("verifying key must be valid");
let proof = Groth16Proof::deserialize_compressed(&proof[..])
.expect("proof must be valid");
let inputs = G1Projective::deserialize_compressed(&inputs[..])
.expect("inputs must be valid");

Groth16::<Bn254>::verify_proof_with_prepared_inputs(&pvk, &proof, &inputs)
.expect("verifying proof should succeed")
}

/// Verify a schnorr signature is valid for the given public key and message
pub fn verify_schnorr(
msg: BlsScalar,
Expand Down
8 changes: 8 additions & 0 deletions rusk-abi/src/host/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ define_cache!(
512,
"RUSK_ABI_PLONK_CACHE_SIZE"
);
define_cache!(
get_groth16_verification,
put_groth16_verification,
with_groth16_cache,
bool,
512,
"RUSK_ABI_GROTH16_CACHE_SIZE"
);
define_cache!(
get_bls_verification,
put_bls_verification,
Expand Down
9 changes: 5 additions & 4 deletions rusk-abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ mod abi;
#[cfg(feature = "abi")]
pub use abi::{
block_height, chain_id, hash, owner, owner_raw, poseidon_hash, self_owner,
self_owner_raw, verify_bls, verify_bls_multisig, verify_proof,
verify_schnorr,
self_owner_raw, verify_bls, verify_bls_multisig, verify_groth16_bn254,
verify_plonk, verify_schnorr,
};

#[cfg(feature = "abi")]
Expand All @@ -55,7 +55,7 @@ mod host;
#[cfg(feature = "host")]
pub use host::{
hash, new_ephemeral_vm, new_genesis_session, new_session, new_vm,
poseidon_hash, verify_bls, verify_bls_multisig, verify_proof,
poseidon_hash, verify_bls, verify_bls_multisig, verify_plonk,
verify_schnorr,
};
#[cfg(feature = "host")]
Expand All @@ -78,7 +78,8 @@ enum Query {}
impl Query {
pub const HASH: &'static str = "hash";
pub const POSEIDON_HASH: &'static str = "poseidon_hash";
pub const VERIFY_PROOF: &'static str = "verify_proof";
pub const VERIFY_PLONK: &'static str = "verify_plonk";
pub const VERIFY_GROTH16_BN254: &'static str = "verify_groth16_bn254";
pub const VERIFY_SCHNORR: &'static str = "verify_schnorr";
pub const VERIFY_BLS: &'static str = "verify_bls";
pub const VERIFY_BLS_MULTISIG: &'static str = "verify_bls_multisig";
Expand Down
Loading

0 comments on commit 1c1137b

Please sign in to comment.