Skip to content

Commit

Permalink
feat: added verifying functions and test cases on Summa contract
Browse files Browse the repository at this point in the history
  • Loading branch information
sifnoc committed Feb 22, 2024
1 parent 4b7f49b commit 37bb1bd
Show file tree
Hide file tree
Showing 6 changed files with 320 additions and 123 deletions.
6 changes: 3 additions & 3 deletions contracts/src/GrandsumVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ contract GrandsumVerifier {
address vk,
bytes calldata proof,
uint256[] calldata values
) public view returns (bool) {
) public returns (bool) {
assembly {
// Check if EC point (x, y) is on the curve.
// if the point is on the affine plane, it then returns updated (success).
Expand Down Expand Up @@ -185,7 +185,7 @@ contract GrandsumVerifier {

// Checking from calldata for grand sum proof
let proof_pos := add(PROOF_CPTR, double_shift_pos)
success := check_ec_point(success, PROOF_CPTR, q)
success := check_ec_point(success, proof_pos, q)
if iszero(success) {
mstore(0, "Opening point is not EC point")
revert(0, 0x20)
Expand All @@ -200,7 +200,7 @@ contract GrandsumVerifier {
}

// Return 1 as result if everything succeeds
mstore(0x00, 1)
mstore(0x00, success)
return(0x00, 0x20)
}
}
Expand Down
32 changes: 10 additions & 22 deletions contracts/src/InclusionVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ contract InclusionVerifier {
uint256[] calldata challenges,
uint256[] calldata values
) public view returns (bool) {
// G2Point memory itermediate_g2 = g2_to_c(vk, challengeScalar);
// g2_tau_g2c(vk, itermediate_g2);

assembly {
// Check EC point (x, y) is on the curve.
// the point is on affine plane, and then return success.
Expand Down Expand Up @@ -98,7 +95,6 @@ contract InclusionVerifier {
mstore(0x120, mload(NEG_S_G2_X_2_MPTR))
mstore(0x140, mload(NEG_S_G2_Y_1_MPTR))
mstore(0x160, mload(NEG_S_G2_Y_2_MPTR))
// revert(0, 0x180)
ret := and(success, staticcall(gas(), 0x08, 0x00, 0x180, 0x00, 0x20))
ret := and(ret, mload(0x00))
}
Expand All @@ -124,17 +120,15 @@ contract InclusionVerifier {
// Ensure the proof length is divisible by `0x80`, accommodating the structured data layout.
success := and(success, eq(0, mod(proof_length, 0x80)))
if iszero(success) {
mstore(0, "Invalid proof length")
revert(0, 0x20)
revert(0, 0)
}

// Load the NEG_S_G2 point with the calculated point
let challenges_length_pos := add(add(PROOF_LEN_CPTR, proof_length), 0x20)
let challenges_length := calldataload(challenges_length_pos)
success := and(success, eq(challenges_length, 4))
if iszero(success) {
mstore(0, "Invalid number of challenges")
revert(0, 0x20)
revert(0, 0)
}

mstore(NEG_S_G2_X_1_MPTR, calldataload(add(challenges_length_pos, 0x20)))
Expand All @@ -149,8 +143,7 @@ contract InclusionVerifier {
// The proof length should match 4 times the length of the evaluation values.
success := and(success, eq(4, div(proof_length, mul(evaluation_values_length, 0x20))))
if iszero(success) {
mstore(0, "Number of evaluation mismatch")
revert(0, 0x20)
revert(0, 0)
}

for { let i := 0 } lt(i, evaluation_values_length) { i := add(i, 1) } {
Expand All @@ -166,8 +159,7 @@ contract InclusionVerifier {
mstore(0xc0, minus_z)
success := and(success, ec_mul_tmp(success, minus_z))
if iszero(success) {
mstore(0, "Failed to multiply G1 by minus_z")
revert(0, 0x80)
revert(0, 0)
}

// Performaing like `c_g_to_minus_z = c + g_to_minus_z` in `verify_kzg_proof` function that is located in `amortized_kzg.rs`.
Expand All @@ -177,40 +169,36 @@ contract InclusionVerifier {
let commitment_proof_pos := add(add(PROOF_CPTR, div(proof_length, 2)), double_shift_pos)
success := check_ec_point(success, commitment_proof_pos, q)
if iszero(success) {
mstore(0, "Commitment point is not EC point")
revert(0, 0x20)
revert(0, 0)
}

let lhs_x := calldataload(commitment_proof_pos) // C_X
let lhs_y := calldataload(add(commitment_proof_pos, 0x20)) // C_Y
success := ec_add_tmp(success, lhs_x, lhs_y)
if iszero(success) {
mstore(0, "Failed to add C and g_to_minus_z")
revert(0, 0x20)
revert(0, 0)
}

mstore(LHS_X_MPTR, mload(0x80))
mstore(LHS_Y_MPTR, mload(0xa0))

// Checking from calldata
let proof_pos := add(PROOF_CPTR, double_shift_pos)
success := check_ec_point(success, PROOF_CPTR, q)
success := check_ec_point(success, proof_pos, q)
if iszero(success) {
mstore(0, "Opening point is not EC point")
revert(0, 0x20)
revert(0, 0)
}
let rhs_x := calldataload(proof_pos) // PI_X
let rhs_y := calldataload(add(proof_pos, 0x20)) // PI_Y

success := and(success, ec_pairing(success, mload(LHS_X_MPTR), mload(LHS_Y_MPTR), rhs_x, rhs_y))
if iszero(success) {
mstore(0, "Failed to perform pairing check")
revert(0, 0x20)
revert(0, 0)
}
}

// Return 1 as result if everything succeeds
mstore(0x00, 1)
mstore(0x00, success)
return(0x00, 0x20)
}
}
Expand Down
82 changes: 70 additions & 12 deletions contracts/src/Summa.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pragma solidity ^0.8.18;
import "@openzeppelin/contracts/access/Ownable.sol";

import "./interfaces/IVerifier.sol";
import "./interfaces/IInclusionVerifier.sol";

contract Summa is Ownable {
/**
Expand Down Expand Up @@ -51,26 +52,37 @@ contract Summa is Ownable {

// zkSNARK verifier of the valid polynomial encoding
IVerifier private immutable polynomialEncodingVerifier;

// KZG verifier of the grand sum
IVerifier private immutable grandSumVerifier;

// KZG verifier of the inclusion proof
IInclusionVerifier private immutable inclusionVerifier;

event AddressOwnershipProofSubmitted(
AddressOwnershipProof[] addressOwnershipProofs
);
event LiabilitiesCommitmentSubmitted(
uint256 indexed timestamp,
uint256[] totalBalances,
bytes proof
);

/**
* Summa contract
* @param _verifyingKey The address of the verification key contract
* @param _polynomialEncodingVerifier the address of the polynomial encoding zkSNARK verifier
* @param _grandSumVerifier the address of the grand sum KZG verifier
* @param _inclusionVerifier the address of the inclusion KZG verifier
* @param cryptocurrencyNames the names of the cryptocurrencies whose balances are encoded in the polynomials
* @param cryptocurrencyChains the chain names of the cryptocurrencies whose balances are encoded in the polynomials
* @param balanceByteRange maximum accepted byte range for the balance of a cryptocurrency
*/
constructor(
address _verifyingKey,
IVerifier _polynomialEncodingVerifier,
IVerifier _grandSumVerifier,
IInclusionVerifier _inclusionVerifier,
string[] memory cryptocurrencyNames,
string[] memory cryptocurrencyChains,
uint8 balanceByteRange
Expand Down Expand Up @@ -101,6 +113,16 @@ contract Summa is Ownable {
"Invalid polynomial encoding verifier address"
);
polynomialEncodingVerifier = _polynomialEncodingVerifier;
require(
address(_grandSumVerifier) != address(0),
"Invalid grandsum verifier address"
);
grandSumVerifier = _grandSumVerifier;
require(
address(_inclusionVerifier) != address(0),
"Invalid inclusion verifier address"
);
inclusionVerifier = _inclusionVerifier;
config = SummaConfig(
cryptocurrencyNames,
cryptocurrencyChains,
Expand Down Expand Up @@ -193,28 +215,64 @@ contract Summa is Ownable {

/**
* @dev Submit commitment for a CEX
* @param proof ZK proof of the valid polynomial encoding
* @param snarkProof ZK proof of the valid polynomial encoding
* @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 proof,
bytes memory snarkProof,
bytes memory grandsumProof,
uint256[] memory totalBalances,
uint256 timestamp
) public onlyOwner {
require(proof.length == 5376, "Invalid proof length");
// 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");

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)
require(
polynomialEncodingVerifier.verifyProof(verifyingKey, proof, args),
"Invalid proof"
polynomialEncodingVerifier.verifyProof(verifyingKey, snarkProof, args),
"Invalid snark proof"
);
// TODO slice the proof to get the ID and balance commitments
// require(
// balanceCommitments.length == config.cryptocurrencies.length,
// "Liability commitments and cryptocurrencies number mismatch"
// );
require(
totalBalances.length == config.cryptocurrencyNames.length,
"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.
}

// 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 grandsum proof");

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

emit LiabilitiesCommitmentSubmitted(timestamp, totalBalances, slicedSnarkProof);
}

commitments[timestamp] = proof;
function verifyInclusionProof(
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");

emit LiabilitiesCommitmentSubmitted(timestamp, proof);
return inclusionVerifier.verifyProof(verifyingKey, inclusionProof, challenges, values);
}
}
22 changes: 22 additions & 0 deletions contracts/src/interfaces/IInclusionVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;

/**
* @dev Zero-knowledge proof verifier
*/
interface IInclusionVerifier {
/**
* @dev Verify a proof
* @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
* @return true if the proof is valid, false otherwise
*/
function verifyProof(
address vk,
bytes calldata proof,
uint256[] calldata challenges,
uint256[] calldata values
) external view returns (bool);
}
Loading

0 comments on commit 37bb1bd

Please sign in to comment.