Skip to main content

Plonky2 Verifier

settlementPlonky2Pallet

Statement hash components

  • context: keccak256(b"plonky2")
  • vk: keccak256(vk.encode())
  • pubs: keccak256(pubs)

Verifier implementation

Assume we have built plonky2 circuit and proved it:

let data = builder.build::<C>();

let proof = data.prove(pw)?;

Verification Key

Plonky2 needs the GateSerializer trait to serialize VerifierCircuitData; for that please use ZKVerifyGateSerializer, since we will deserialize against it as well.

use plonky2_verifier::ZKVerifyGateSerializer;

let vk_bytes = data
.verifier_data()
.to_bytes(&ZKVerifyGateSerializer)?;

Proof

let mut proof_bytes = Vec::new();
proof_bytes.write_proof(&proof.proof)?;

Public Inputs

Plonky2 keeps Proof with Pubs in one struct, while zkVerify requires these to be split.

let mut pubs_bytes = Vec::new();
pubs_bytes.write_usize(proof.public_inputs.len())?;
pubs_bytes.write_field_vec(proof.public_inputs.as_slice())?;

Config

Plonky2 has generic-based configuration for its plonk: config.rs. Things like hashing algorithm, field, etc. Due to limited support for passing them in zkVerify, we support only two preset configs over Keccak with Goldilocks and Poseidon with Goldilocks.

Therefore, we use custom format for representing Vk - particularly, JSON of this form:

{
"config": "Poseidon",
"bytes": "392093829392..."
}

Here bytes is hex-encoded representation of vk_bytes we computed earlier, and config is merely either Keccak or Poseidon.

You can leverage our CLI tool in order to transform your Vk into the one acceptable by zkVerify format - please see plonky2-converter.

Result

The submitProof exstrinsic can fail either if it's not possible to deserialize the proof (InvalidProofData), or if the proof doesn't verify (VerifyError).