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

Implement Verifiers for KZG and SNARK Proofs in Contracts #267

Merged
merged 18 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,28 @@

pragma solidity ^0.8.0;

contract GrandsumVerifier {
contract GrandSumVerifier {
// Calldata positions for proofs
uint256 internal constant PROOF_LEN_CPTR = 0x64;
uint256 internal constant PROOF_CPTR = 0x84;

// Memory positions for the verifying key.
// The memory location starts at 0x200 due to the maximum operation on the ec_pairing function being 0x180, marking the maximum memory location used
uint256 internal constant VK_MPTR = 0x200;
uint256 internal constant VK_DIGEST_MPTR = 0x200;
uint256 internal constant K_MPTR = 0x220;
uint256 internal constant N_INV_MPTR = 0x240;
uint256 internal constant OMEGA_MPTR = 0x260;
uint256 internal constant OMEGA_INV_MPTR = 0x280;
uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x2a0;
uint256 internal constant NUM_INSTANCES_MPTR = 0x2c0;
uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x2e0;
uint256 internal constant ACC_OFFSET_MPTR = 0x300;
uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x320;
uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x340;
uint256 internal constant G1_X_MPTR = 0x360;
uint256 internal constant G1_Y_MPTR = 0x380;
uint256 internal constant G2_X_1_MPTR = 0x3a0;
uint256 internal constant G2_X_2_MPTR = 0x3c0;
uint256 internal constant G2_Y_1_MPTR = 0x3e0;
uint256 internal constant G2_Y_2_MPTR = 0x400;
uint256 internal constant NEG_S_G2_X_1_MPTR = 0x420;
uint256 internal constant NEG_S_G2_X_2_MPTR = 0x440;
uint256 internal constant NEG_S_G2_Y_1_MPTR = 0x460;
uint256 internal constant NEG_S_G2_Y_2_MPTR = 0x480;

uint256 internal constant LHS_X_MPTR = 0x4a0;
uint256 internal constant LHS_Y_MPTR = 0x4c0;
uint256 internal constant N_INV_MPTR = 0x220;
uint256 internal constant LHS_X_MPTR = 0x240;
uint256 internal constant LHS_Y_MPTR = 0x260;
uint256 internal constant G1_X_MPTR = 0x280;
uint256 internal constant G1_Y_MPTR = 0x2a0;
uint256 internal constant G2_X_1_MPTR = 0x2c0;
uint256 internal constant G2_X_2_MPTR = 0x2e0;
uint256 internal constant G2_Y_1_MPTR = 0x300;
uint256 internal constant G2_Y_2_MPTR = 0x320;
uint256 internal constant NEG_S_G2_X_1_MPTR = 0x340;
uint256 internal constant NEG_S_G2_X_2_MPTR = 0x360;
uint256 internal constant NEG_S_G2_Y_1_MPTR = 0x380;
uint256 internal constant NEG_S_G2_Y_2_MPTR = 0x3a0;



function verifyProof(
address vk,
Expand Down Expand Up @@ -106,10 +96,10 @@ contract GrandsumVerifier {
// Initialize success as true
let success := true

// Copy part of the vk into memory.
// The address 0x02a0 marks the end location that `neg_s_g2` points to in the vk contract.
// This step is for verifying the opening proof; the permutation commitments in the vk contract are not needed.
extcodecopy(vk, VK_MPTR, 0x00, 0x02a0)
// Copy part of the verifying key contract into memory.
extcodecopy(vk, N_INV_MPTR, 0x40, 0x020)
// The address 0x02a0(= 0x160 + 0x140) indicates the memory location to which `neg_s_g2` points in the verifying key contract
extcodecopy(vk, G1_X_MPTR, 0x160, 0x140)

// The proof length should be divisible by `0x80` bytes, equivalent to four words.
//
Expand Down
31 changes: 15 additions & 16 deletions contracts/src/InclusionVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@ contract InclusionVerifier {

// Memory positions for the verifying key.
// The memory location starts at 0x200 due to the maximum operation on the ec_pairing function being 0x180.
uint256 internal constant VK_MPTR = 0x200;
uint256 internal constant LHS_X_MPTR = 0x2e0;
uint256 internal constant LHS_Y_MPTR = 0x300;
uint256 internal constant G1_X_MPTR = 0x360;
uint256 internal constant G1_Y_MPTR = 0x380;
uint256 internal constant G2_X_1_MPTR = 0x3a0;
uint256 internal constant G2_X_2_MPTR = 0x3c0;
uint256 internal constant G2_Y_1_MPTR = 0x3e0;
uint256 internal constant G2_Y_2_MPTR = 0x400;
uint256 internal constant NEG_S_G2_X_1_MPTR = 0x420;
uint256 internal constant NEG_S_G2_X_2_MPTR = 0x440;
uint256 internal constant NEG_S_G2_Y_1_MPTR = 0x460;
uint256 internal constant NEG_S_G2_Y_2_MPTR = 0x480;
uint256 internal constant LHS_X_MPTR = 0x200;
uint256 internal constant LHS_Y_MPTR = 0x220;
uint256 internal constant G1_X_MPTR = 0x240;
uint256 internal constant G1_Y_MPTR = 0x260;
uint256 internal constant G2_X_1_MPTR = 0x280;
uint256 internal constant G2_X_2_MPTR = 0x2a0;
uint256 internal constant G2_Y_1_MPTR = 0x2c0;
uint256 internal constant G2_Y_2_MPTR = 0x2e0;
uint256 internal constant NEG_S_G2_X_1_MPTR = 0x300;
uint256 internal constant NEG_S_G2_X_2_MPTR = 0x320;
uint256 internal constant NEG_S_G2_Y_1_MPTR = 0x340;
uint256 internal constant NEG_S_G2_Y_2_MPTR = 0x360;

function verifyProof(
address vk,
Expand Down Expand Up @@ -106,9 +105,9 @@ contract InclusionVerifier {
// Initialize success as true
let success := true

// Copy variables from the verifying key until `neg_s_g2`
extcodecopy(vk, VK_MPTR, 0x00, 0x0220)
// Copy the six variables from the verifying key up to the memory address 0x200 (= 0x160 + 0xc0), where `g2_y_2` is located.
extcodecopy(vk, G1_X_MPTR, 0x160, 0xc0)

// The proof length should be divisible by `0x80` bytes, equivalent to four words.
// The proof is structured as follows:
// 2W * n: Commitment points in the SNARK proof.
Expand Down
53 changes: 27 additions & 26 deletions contracts/src/Summa.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ contract Summa is Ownable {
event LiabilitiesCommitmentSubmitted(
uint256 indexed timestamp,
uint256[] totalBalances,
bytes proof
bytes snarkProof,
bytes grandSumProof
);

/**
Expand Down Expand Up @@ -115,7 +116,7 @@ contract Summa is Ownable {
polynomialEncodingVerifier = _polynomialEncodingVerifier;
require(
address(_grandSumVerifier) != address(0),
"Invalid grandsum verifier address"
"Invalid grand sum verifier address"
);
grandSumVerifier = _grandSumVerifier;
require(
Expand Down Expand Up @@ -216,20 +217,20 @@ contract Summa is Ownable {
/**
* @dev Submit commitment for a CEX
* @param snarkProof ZK proof of the valid polynomial encoding
* @param grandsumProof kzg proof of the grand sum
* @param grandSumProof kzg proof of the grand sum
* @param totalBalances The array of total balances in the grand sum
* @param timestamp The timestamp at which the CEX took the snapshot of its assets and liabilities
*/
function submitCommitment(
bytes memory snarkProof,
bytes memory grandsumProof,
bytes calldata snarkProof,
bytes calldata grandSumProof,
uint256[] memory totalBalances,
uint256 timestamp
) public onlyOwner {
// Check input lengths
require(totalBalances.length > 0, "Invalid total balances length");
require(grandsumProof.length == (totalBalances.length * 0x40), "Invalid grandsum proof length");
require(snarkProof.length > grandsumProof.length, "Invalid snark proof length");
require(grandSumProof.length == (totalBalances.length * 0x40), "Invalid grand sum proof length");
require(snarkProof.length > grandSumProof.length, "Invalid snark proof length");

uint[] memory args = new uint[](1);
args[0] = 1; // Workaround to satisfy the verifier (TODO remove after https://github.com/summa-dev/halo2-solidity-verifier/issues/1 is resolved)
Expand All @@ -242,37 +243,37 @@ contract Summa is Ownable {
"Liability commitments and cryptocurrencies number mismatch"
);

bytes memory slicedSnarkProof = new bytes(grandsumProof.length);
for (uint256 i = 0; i < grandsumProof.length; i++) {
slicedSnarkProof[i] = snarkProof[i + 64]; // Skip first 64 bytes, it's not for total balance.
}
bytes calldata slicedSnarkProof = snarkProof[0:64 + grandSumProof.length];
bytes memory combinedProofs = abi.encodePacked(grandSumProof, slicedSnarkProof[64:]);

// Concatenate the grandsumProof with snarkProof with same length
bytes memory combinedProofs = new bytes(slicedSnarkProof.length + grandsumProof.length);
for (uint256 i = 0; i < grandsumProof.length; i++) {
combinedProofs[i] = grandsumProof[i];
}
for (uint256 i = 0; i < slicedSnarkProof.length; i++) {
combinedProofs[i + grandsumProof.length] = slicedSnarkProof[i];
}
require(grandSumVerifier.verifyProof(verifyingKey, combinedProofs, totalBalances), "Invalid grand sum proof");

require(grandSumVerifier.verifyProof(verifyingKey, combinedProofs, totalBalances), "Invalid grandsum proof");

// Slice the proof aa length as grandsumProof
commitments[timestamp] = slicedSnarkProof;

emit LiabilitiesCommitmentSubmitted(timestamp, totalBalances, slicedSnarkProof);
emit LiabilitiesCommitmentSubmitted(timestamp, totalBalances, slicedSnarkProof, grandSumProof);
}

function verifyInclusionProof(
uint256 timestamp,
bytes memory inclusionProof,
uint256[] memory challenges,
uint256[] memory values
) public view returns (bool) {
require(values.length > 1, "Invalid values length");
require(inclusionProof.length == (values.length * 0x80), "Invalid inclusion proof length");
require(challenges.length == 4, "Invalid challenges length");

// Excluding `usename` in values
require((values.length - 1) == config.cryptocurrencyNames.length, "Values length mismatch with config");

bytes memory snarkProof = commitments[timestamp];

bytes memory combinedProofs = new bytes(snarkProof.length + inclusionProof.length);
for (uint256 i = 0; i < inclusionProof.length; i++) {
combinedProofs[i] = inclusionProof[i];
}
for (uint256 i = 0; i < snarkProof.length; i++) {
combinedProofs[i + inclusionProof.length] = snarkProof[i];
}

return inclusionVerifier.verifyProof(verifyingKey, inclusionProof, challenges, values);
return inclusionVerifier.verifyProof(verifyingKey, combinedProofs, challenges, values);
}
}
2 changes: 1 addition & 1 deletion contracts/src/interfaces/IInclusionVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface IInclusionVerifier {
* @param vk The verification key
* @param proof The proof
* @param challenges The pre-calculated g2 points with challenge
* @param values The user data that includes username, balance of currency 1
* @param values The user data that includes userId, balance of currency 1
* @return true if the proof is valid, false otherwise
*/
function verifyProof(
Expand Down
Loading
Loading