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

111 test kzgv2 on bn254 #112

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 53 additions & 2 deletions contracts/algebra/bn254.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,59 @@ library bn254_crypto {
});
}

// ECADD
function ecadd(types.g1_point memory a, types.g1_point memory b)
internal view returns(types.g1_point memory res)
{
validateG1Point(a);
validateG1Point(b);
bool success;

assembly {
let mPtr := mload(0x40)
mstore(mPtr, mload(a))
mstore(add(mPtr, 0x20), mload(add(a, 0x20)))
mstore(add(mPtr, 0x40), mload(b))
mstore(add(mPtr, 0x60), mload(add(b, 0x20)))
success := staticcall(
gas(),
6,
mPtr,
0x80,
mload(res),
0x40
)
}
require(success, "ECADD check failed!");
}

// ECMUL
function ecmul(types.g1_point memory a, uint256 s)
internal view returns(types.g1_point memory res)
{
validateG1Point(a);
bool success;

assembly {
let mPtr := mload(0x40)
mstore(mPtr, mload(a))
mstore(add(mPtr, 0x20), mload(add(a, 0x20)))
mstore(add(mPtr, 0x40), s)
success := staticcall(
gas(),
6,
mPtr,
0x60,
mload(res),
0x40
)
}
require(success, "ECMUL check failed!");
}


/// Evaluate the following pairing product:
/// e(a1, a2).e(-b1, b2) == 1
/// e(a1, a2).e(b1, b2) == 1
function pairingProd2(
types.g1_point memory a1,
types.g2_point memory a2,
Expand Down Expand Up @@ -159,4 +210,4 @@ library bn254_crypto {
}
require(is_well_formed, "Bn254: G1 point not on curve, or is malformed");
}
}
}
122 changes: 122 additions & 0 deletions contracts/commitments/batched_kzg_verifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: Apache-2.0.
//---------------------------------------------------------------------------//
// Copyright (c) 2024 Vasiliy Olekhov <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//---------------------------------------------------------------------------//
pragma solidity >=0.8.4;

import "../types.sol";
import "./batched_fri_verifier.sol";
import "../algebra/polynomial.sol";
import "../basic_marshalling.sol";
import "../algebra/bn254.sol";
import "../../contracts/interfaces/modular_verifier.sol";

import "hardhat/console.sol";

library batched_kzg_verifier {

function verify_proof(
types.g1_point[] memory commitments,
uint256[] memory Z,
uint256[] memory U,
types.transcript_data memory tr_state,
types.kzg_params_type memory kzg_params,
types.kzg_proof_type memory kzg_proof)
internal view returns (bool result) {
unchecked {

uint256 i;

/* 1. send to transcript all commitments */
for (i = 0; i < kzg_params.commitments_num; ++i ) {
transcript.update_transcript_b32(tr_state, bytes32(commitments[i].x));
transcript.update_transcript_b32(tr_state, bytes32(commitments[i].y));
}
for (i = 0; i < kzg_params.points_num; ++i ) {
transcript.update_transcript_b32(tr_state, bytes32(Z[i]));
}
for (i = 0; i < kzg_params.points_num; ++i ) {
transcript.update_transcript_b32(tr_state, bytes32(U[i]));
}
/* TWICE ? */
for (i = 0; i < kzg_params.commitments_num; ++i ) {
transcript.update_transcript_b32(tr_state, bytes32(commitments[i].x));
transcript.update_transcript_b32(tr_state, bytes32(commitments[i].y));
}
for (i = 0; i < kzg_params.points_num; ++i ) {
transcript.update_transcript_b32(tr_state, bytes32(Z[i]));
}
for (i = 0; i < kzg_params.points_num; ++i ) {
transcript.update_transcript_b32(tr_state, bytes32(U[i]));
}

/* 2. challenge theta from transcript */
uint256 theta = transcript.get_field_challenge(tr_state, bn254_crypto.r_mod);

/* 3. send pi_1 to transcript */
transcript.update_transcript_b32(tr_state, bytes32(kzg_proof.pi_1.x));
transcript.update_transcript_b32(tr_state, bytes32(kzg_proof.pi_1.y));

/* 4. challenge theta_2 from transcript */
uint256 theta_2 = transcript.get_field_challenge(tr_state, bn254_crypto.r_mod);

/* check theta and theta_2 values */
if(theta != kzg_params.theta) {
console.log("wrong theta: ", theta);
console.log("expecting : ", kzg_params.theta);
}

if(theta_2 != kzg_params.theta_2) {
console.log("wrong theta_2 :", theta_2);
console.log("expecting : ", kzg_params.theta_2);
}

/* 5. for a set of commitments construct F */

uint256 theta_i = 1;
types.g1_point memory F = bn254_crypto.new_g1(0,0);
uint256 rsum = 0;
uint256 tmp;
uint256 r_i;

for (i = 0; i < kzg_params.commitments_num; ++i) {
tmp = 13537094572093675138513973797244805699587981214733746302150278342976640424397;
r_i = mulmod(theta_i, tmp, bn254_crypto.r_mod);
types.g1_point memory f = bn254_crypto.ecmul(commitments[i], r_i);
F = bn254_crypto.ecadd(F, f);
tmp = 9554926369995100646077410167290930878381045633071770559944038420370185418405;
r_i = mulmod(r_i, tmp, bn254_crypto.r_mod);
rsum = addmod(rsum, r_i, bn254_crypto.r_mod);
theta_i = mulmod(theta_i, theta, bn254_crypto.r_mod);
}

types.g1_point memory F_last = bn254_crypto.ecmul(bn254_crypto.P1(), rsum);
F_last.x = bn254_crypto.p_mod - F_last.x;
F = bn254_crypto.ecadd(F, F_last);

tmp= 11559732032986387107991004021392285783925812861821192530917403151452391805634;
F_last = bn254_crypto.ecmul(kzg_proof.pi_1, tmp);
F_last.x = bn254_crypto.p_mod - F_last.x;
F = bn254_crypto.ecadd(F, F_last);

F_last = bn254_crypto.ecmul(kzg_proof.pi_1, theta_2);
F = bn254_crypto.ecadd(F, F_last);

types.g2_point memory g2 = bn254_crypto.P2();

return bn254_crypto.pairingProd2(F , g2, kzg_proof.pi_2, kzg_params.verification_key);
}
}
}
123 changes: 123 additions & 0 deletions contracts/test/bn254/bn254_test.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//---------------------------------------------------------------------------//
// Copyright (c) 2024 Vasiliy Olekhov <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//---------------------------------------------------------------------------//
pragma solidity ^0.8.0;

import '../../../contracts/commitments/batched_kzg_verifier.sol';
import "../../../contracts/interfaces/modular_verifier.sol";
import 'hardhat/console.sol';

contract kzg_estimation is IModularVerifier {

/**
* @dev Initializes verifier
*/
function initialize(
address lookup_argument_contract_address,
address gate_argument_contract_address,
address commitment_contract_address) public
{

}

/**
* @dev Verifies proof
*/
function verify(
bytes calldata blob,
uint256[] calldata public_input
) public returns (bool result)
{

types.g1_point[] memory commitments;
commitments = new types.g1_point[](4);

commitments[0].x = 0x0c44878bb8ff269d74d4c82a460b47503e72178c24ea96b071db39f540083856;
commitments[0].y = 0x15e1d289c6429156a6812b89f5f2b9c5adbcae41274c88a317d7b394e15a339;
commitments[1].x = 0x1a61eddcc2d2c249e4fea2895bf5d5c258dccd230ce16b355e22da9ccef3d796;
commitments[1].y = 0x88dfa0426989fe5b61b796b53fb18bd72b74bc513524e62ba8c0651366d1e96;
commitments[2].x = 0x00a81266b641f4305269eaf67036ee6a5d532143cbc706c1e97c7a84ba769d14;
commitments[2].y = 0x347d40c1e4471ca1423f38a73aec0a009819eff6571813db1620156d4719b67;
commitments[3].x = 0x5804dfe02a750643061c878b6d938cb74c621375c63c77cde1eb3804b8206d80;
commitments[3].y = 0x2501fa3f32e1cd9b04d66803dc467373c9f4f8fe285e2d53422fe9e508fe75e3;

uint256[] memory Z;
Z = new uint256[](12);
Z[ 0] = 0x0000000000000000000000000000000000000000000000000000000000000701;
Z[ 1] = 0x000000000000000000000000000000000000000000000000000000000000601c;
Z[ 2] = 0x000000000000000000000000000000000000000000000000000312e5a822d164;
Z[ 3] = 0x00000000000000000000000000000000000000000000000000000000000010f7;
Z[ 4] = 0x000000000000000000000000000000000000000000000000000000000000e03c;
Z[ 5] = 0x00000000000000000000000000000000000000000000000000076a1399d05b27;
Z[ 6] = 0x00000000000000000000000000000000000000000000000000000000000000c4;
Z[ 7] = 0x0000000000000000000000000000000000000000000000000000000000001aed;
Z[ 8] = 0x000000000000000000000000000000000000000000000000000000000001605c;
Z[ 9] = 0x00000000000000000000000000000000000000000000000000000000000024e3;
Z[10] = 0x000000000000000000000000000000000000000000000000000000000001e07c;
Z[11] = 0x0000000000000000000000000000000000000000000000000011eef27398435f;

uint256[] memory U;
U = new uint256[](12);
U[ 0] = 0x0000000000000000000000000000000000000000000000000000007c9471f41d;
U[ 1] = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f52c1ef629ad;
U[ 2] = 0x00000000000000000000000000000000000000000000000000000014c3686fe3;
U[ 3] = 0x000000000000000000000000000000000000000000000000000001267d4b52fb;
U[ 4] = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f49e87961425;
U[ 5] = 0x0000000000000000000000000000000000000000000000000000003114e2256d;
U[ 6] = 0x00000000000000000000000000000000000000000000000000000000000111e1;
U[ 7] = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effe5941;
U[ 8] = 0x00000000000000000000000000000000000000000000000000000000000095a3;
U[ 9] = 0x000000000000000000000000000000000000000000000000000002ac7f620cdf;
U[10] = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f35985d7ec49;
U[11] = 0x00000000000000000000000000000000000000000000000000000072153b8fdd;

types.kzg_params_type memory kzg_params;

kzg_params.commitments_num = 4;
kzg_params.points_num = 12;
kzg_params.theta = 0x146669b8f0f804db1f65879b69ebd1eb5a62d5a304f397fe2214f1a09512289;
kzg_params.theta_2 = 0x60ccd0177322ae60e62f674ae1f0594ef507a2296f0fe7ea45537a2493e5c6a;
kzg_params.verification_key = bn254_crypto.new_g2(
18551411094430470096460536606940536822990217226529861227533666875800903099477,
15512671280233143720612069991584289591749188907863576513414377951116606878472,
1711576522631428957817575436337311654689480489843856945284031697403898093784,
13376798835316611669264291046140500151806347092962367781523498857425536295743);


types.kzg_proof_type memory kzg_proof;
kzg_proof.pi_1 = bn254_crypto.new_g1(
0x2a5962762ebd3540336267427860b210e8cd10ceb111d10c279ca20d3419c36f,
0x79cc53475493803aac3f585ccaf63d893d009dc8c143160098327542c4c6d87);
kzg_proof.pi_2 = bn254_crypto.new_g1(
0x28fbae026e8b174c26e0ab3ad4d3e523fa0ed914cfc4b81d206b985108471305,
0x21532211d9b11dc61e52f52f66f2408d577278b6fc33c6fe83f3a8d089ad1a1c);
/*
kzg_proof.pi_1 = bn254_crypt.new_g1(
0x2a5962762ebd3540336267427860b210e8cd10ceb111d10c279ca20d3419c36f,
0x79cc53475493803aac3f585ccaf63d893d009dc8c143160098327542c4c6d87);
kzg_proof.pi_2 = bn254_crypt.new_g1(
0x28fbae026e8b174c26e0ab3ad4d3e523fa0ed914cfc4b81d206b985108471305,
0x21532211d9b11dc61e52f52f66f2408d577278b6fc33c6fe83f3a8d089ad1a1c);
*/

types.transcript_data memory tr_state;
transcript.init_transcript(tr_state, hex"");

result = batched_kzg_verifier.verify_proof(commitments, Z, U, tr_state, kzg_params, kzg_proof);
emit VerificationResult(result);
}

}
14 changes: 14 additions & 0 deletions contracts/types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,20 @@ library types {
uint256[] fri_roots; // It should be bytes32
}


struct kzg_params_type {
uint256 commitments_num;
uint256 theta;
uint256 theta_2;
uint256 points_num;
types.g2_point verification_key;
}

struct kzg_proof_type {
types.g1_point pi_1;
types.g1_point pi_2;
}

struct fri_state_type {
bytes b;
//0x0
Expand Down
15 changes: 15 additions & 0 deletions deploy/test-kzg-verifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const hre = require('hardhat')
const {getNamedAccounts} = hre

module.exports = async function () {
const {deployments, getNamedAccounts} = hre;
const {deploy} = deployments;
const {deployer, tokenOwner} = await getNamedAccounts();

await deploy('kzg_estimation', {
from: deployer,
log: true,
});
}

module.exports.tags = ['testKZGVerifierFixture']
12 changes: 12 additions & 0 deletions tasks/modular-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,15 @@ task("verify-circuit-proof")
let circuit = test.test;
process.exit((await verify_circuit_proof(modular_path, circuit)) ? 0 : 1);
});

task("verify-kzg")
.setAction(async (hre) => {
console.log("Verify KZG");
await deployments.fixture(['testKZGVerifierFixture']);
const v = await ethers.getContract('kzg_estimation');
const proof = [];
const public_input = [];
const receipt = await (await v.verify(proof, public_input, {gasLimit: 30_500_000})).wait();
console.log("⛽Gas used: ", receipt.gasUsed.toNumber());
// console.log(receipt);
});
16 changes: 16 additions & 0 deletions test/kzg-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const hre = require('hardhat')

/* global BigInt */

describe('KZG test', function () {
const {deployments} = hre;

it("Pairing precompile test", async function () {
await deployments.fixture(['testKZGVerifierFixture']);
const v = await ethers.getContract('kzg_estimation');
let x = await v.verify({gasLimit: 30_500_000});
console.log(x.gasUsed);
const receipt = await (await v.test_kzg({gasLimit: 30_500_000})).wait();
console.log("⛽Gas used: ", receipt.gasUsed.toNumber());
});
})
Loading