Skip to main content

🔒 Plonk Verifier Helper

Introduction​

The Verifier Helper library is designed to simplify working with auto-generated verifier contracts from hardhat-zkit to verify Plonk ZK proofs.

Implementation​

Plonk verifier contracts usually have a function verifyProof(uint256[24] proofData_, uint256[<number-of-public-inputs>] inputs_) where the inputs_ is a static array of public inputs the circuit accepts. If a developer needs to interact with more than one circuit verifier, it will be necessary to create many different Solidity interfaces, which is not particularly user-friendly. The PlonkVerifierHelper library solves this problem.

Under the hood, the PlonkVerifierHelper library wraps the verifier staticcall by constructing public signals dynamically. The length of the static array inputs_ inside the verifyProof function is determined by the length of the dynamic array that was passed to the library function.

Functions​

To use the PlonkVerifierHelper library, you need to import it.

import "@solarity/solidity-lib/libs/zkp/PlonkVerifierHelper.sol";

And optionally bind it to the type with the using statement.

using PlonkVerifierHelper for address;

verifyProof​

function verifyProof(
address verifier_,
PlonkProof memory plonkProof_
) internal view returns (bool);
function verifyProof(
address verifier_,
ProofPoints memory proofPoints_,
uint256[] memory pubSignals_
) internal view returns (bool);
function verifyProof(
address verifier_,
uint256[24] memory proofData_,
uint256[] memory pubSignals_
) internal view returns (bool);

Description​

These functions verify the ZK proof by calling the verifyProof function on the verifier's address by converting the dynamic array of public inputs into a static one. The functions will revert if the passed verifier address does not have the required verifyProof method.

Example​

import "@solarity/solidity-lib/libs/zkp/PlonkVerifierHelper.sol";

contract ZKPValidator {
using PlonkVerifierHelper for address;

function verifyProof(
address verifier_,
PlonkVerifierHelper.PlonkProof memory plonkProof_
) external view returns (bool) {
return verifier_.verifyProof(plonkProof_);
}

function verifyZKP(
address verifier_,
PlonkVerifierHelper.ProofPoints memory proofPoints_,
uint256[] memory inputs_
) external view returns (bool) {
return verifier_.verifyProof(proofPoints_, inputs_);
}

function verifyZKP(
address verifier_,
uint256[2] a_,
uint256[2][2] b_,
uint256[2] c_,
uint256[] memory inputs_
) external view returns (bool) {
return verifier_.verifyProof(a_, b_, c_, inputs_);
}
}

ZKPValidator public validator;

validator = new ZKPValidator();

address verifierAddr_ = 0x0Ef6437FC3441A5936f347313D5043FE487a8B54;

uint256[24] proofData_ = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
];

PlonkVerifierHelper.ProofPoints memory proofPoints_ = PlonkVerifierHelper.ProofPoints(proofData_);

uint256[] inputs_ = new uint256[](3);

inputs_[0] = 100;
inputs_[1] = 200;
inputs_[2] = 300;

PlonkVerifierHelper.PlonkProof memory proof_ = PlonkVerifierHelper.PlonkProof(
proofPoints_,
inputs_
);

validator.verifyZKP(verifierAddr_, proof_); // true
validator.verifyZKP(verifierAddr_, proofPoints_, inputs_); // true
validator.verifyZKP(verifierAddr_, proofData_, inputs_); // true

validator.verifyZKP(address(validator_), proofData_, inputs_);
// Reverts with "PlonkVerifierHelper: failed to call verifyProof function"

verifyProofSafe​

 function verifyProofSafe(
address verifier_,
PlonkProof memory plonkProof_,
uint256 pubSignalsCount_
) internal view returns (bool);
function verifyProofSafe(
address verifier_,
ProofPoints memory proofPoints_,
uint256[] memory pubSignals_,
uint256 pubSignalsCount_
) internal view returns (bool);
function verifyProofSafe(
address verifier_,
uint256[2] memory a_,
uint256[2][2] memory b_,
uint256[2] memory c_,
uint256[] memory pubSignals_,
uint256 pubSignalsCount_
) internal view returns (bool);

Description​

These functions work in a similar way to the ones above. However, there is one extra layer of protection: they will revert if the pubSignals_ array length is not equal to the pubSignalsCount_.