Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 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
2 changes: 2 additions & 0 deletions evm-vrfier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ edition = "2021"
alloy = { version = "0.14", default-features = false, features = ["contract", "provider-anvil-node"] }
ark-ff = { workspace = true }
ark-bls12-381 = { version = "0.5", default-features = false, features = ["curve"] }
ark-ed-on-bls12-381-bandersnatch = { version = "0.5", default-features = false }

[dev-dependencies]
tokio = { version = "1.44", default-features = false }
ark-std = { workspace = true }
ark-ec = { workspace = true }
w3f-plonk-common = { path = "../w3f-plonk-common", default-features = false , features = ["std"]}
w3f-pcs = { workspace = true }

[build-dependencies]
Expand Down
3 changes: 3 additions & 0 deletions evm-vrfier/contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ libs = ["lib"]
evm_version = "prague"
via_ir = true

[fmt]
ignore = ["src/SoladyBls.sol"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
97 changes: 97 additions & 0 deletions evm-vrfier/contracts/src/Constraints.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
pragma solidity ^0.8.24;

library Constraints {
uint256 constant domain_size = 256;

uint256 constant w = 36007022166693598376559747923784822035233416720563672082740011604939309541707;
uint256 constant w_inv = 11184958699465346337974417366548385058372410568086779736245770566382283753344;
uint256 constant w_inv_2 = 43775291915288810309377910988321681322896939416379112495208008906206324170002;
uint256 constant w_inv_3 = 24824062393296269928157607240610716359041681219294130923310247842219009400878;
uint256 constant w_inv_4 = 45254319123522011116259460062854627366454101350769349111320208945036885998124;

uint256 constant r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001;
uint256 constant te_coeff_a = r - 5;

function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = addmod(a, b, r);
}

function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = mulmod(a, b, r);
}

function cond_te_addition(
uint256 b,
uint256 x1,
uint256 y1,
uint256 x2,
uint256 y2,
uint256 x3,
uint256 y3,
uint256 not_last
) internal pure returns (uint256 cx, uint256 cy) {
/// `cx = {[(a.x1.x2 + y1.y2).x3 - x1.y1 - x2.y2].b + (x3 - x1).(1 - b)}.not_last`
/// `cy = {[(x1.y2 - x2.y1).y3 - x1.y1 + x2.y2].b + (y3 - y1).(1 - b)}.not_last`
uint256 x1y1 = mul(x1, y1);
uint256 x2y2 = mul(x2, y2);
uint256 one_minus_b = add(1, r - b);
// forgefmt: disable-next-item
cx = mul( // [(a.x1.x2 + y1.y2).x3 - x1.y1 - x2.y2].b
add(
mul(
add(mul(te_coeff_a, mul(x1, x2)), mul(y1, y2)), //a.x1.x2 + y1.y2
x3
),
r - add(x1y1, x2y2)
),
b
);
cx = mul(add(cx, mul(add(x3, r - x1), one_minus_b)), not_last);
// forgefmt: disable-next-item
cy = mul( // [(x1.y2 - x2.y1).y3 - x1.y1 + x2.y2].b
add(
add(
mul(

add(mul(x1, y2), r - mul(x2,y1)), //x1.y2 - x2.y1
y3
),
r - x1y1),
x2y2
),
b
);
cy = mul(add(cy, mul(add(y3, r - y1), one_minus_b)), not_last);
}

function mod_exp(uint256 base, uint256 exp) internal view returns (uint256) {
bytes memory precompileData = abi.encode(32, 32, 32, base, exp, r);
(bool ok, bytes memory data) = address(5).staticcall(precompileData);
require(ok, "expMod failed");
return abi.decode(data, (uint256));
}

function inv(uint256 x) internal view returns (uint256) {
return mod_exp(x, r - 2);
}

function v_at(uint256 z) internal view returns (uint256) {
return mod_exp(z, domain_size) - 1;
}

function v_inv_at(uint256 z) internal view returns (uint256) {
return inv(v_at(z));
}

function v_inv_hiding_at(uint256 z) internal view returns (uint256) {
return mul(mul(mul(v_inv_at(z), add(z, r - w_inv)), add(z, r - w_inv_2)), add(z, r - w_inv_3));
}

function quotient_at(uint256 c, uint256 z) internal view returns (uint256) {
return mul(c, v_inv_hiding_at(z));
}

function not_last_row(uint256 z) internal pure returns (uint256) {
return add(z, r - w_inv_4);
}
}
106 changes: 106 additions & 0 deletions evm-vrfier/contracts/src/Kzg.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
pragma solidity ^0.8.24;

import "./BlsGenerators.sol";

library Kzg {
// Verifies a batch of `2` kzg proofs:
// 1. `proofs[0]` certifying that `polys[i](zs[0]) = evals_at_z1[i], i = 0,...,k, k = evals_at_z1.length`,
// 2. `proofs[1]` certifying that `polys[j](zs[1]) = evals_at_z2[j], j = 0,...,l, l = evals_at_z2.length`.
function verify_plonk_kzg(
BLS.G1Point[] memory polys,
uint256[] memory zs,
uint256[] memory evals_at_z1,
uint256[] memory evals_at_z2,
BLS.G1Point[] memory proofs,
uint256[] memory nus,
// uint256 r,
BLS.G2Point memory tau_g2
) internal view returns (bool) {
uint256 r = 123; //TODO

uint256 k = polys.length;
assert(evals_at_z1.length == k);
assert(nus.length == k);
uint256 l = evals_at_z2.length;
assert(l <= k);

// all the g1 points the verifier knows should go to a single msm
uint256 n_bases = k + 3; // `n` commitments to the polynomials, proofs in `zs[0]` and `zs[1]`, and `g1` to commit to the evaluations

BLS.G1Point[] memory msm_bases = new BLS.G1Point[](n_bases);
bytes32[] memory msm_scalars = new bytes32[](n_bases);

uint256 i;
for (i = 0; i < k; i++) {
msm_bases[i] = polys[i];
}

uint256 r_plus_1 = BlsGenerators.add_fr(r, 1);
for (i = 0; i < l; i++) {
msm_scalars[i] = bytes32(BlsGenerators.mul_fr(r_plus_1, nus[i]));
}
for (i = l; i < k; i++) {
msm_scalars[i] = bytes32(nus[i]);
}

uint256 agg_at_z = 0;
for (i = 0; i < l; i++) {
agg_at_z = BlsGenerators.add_fr(agg_at_z, BlsGenerators.mul_fr(uint256(nus[i]), evals_at_z2[i]));
}
agg_at_z = BlsGenerators.mul_fr(agg_at_z, r);
for (i = 0; i < polys.length; i++) {
agg_at_z = BlsGenerators.add_fr(agg_at_z, BlsGenerators.mul_fr(uint256(nus[i]), evals_at_z1[i]));
}
msm_bases[i] = BlsGenerators.G1();
msm_scalars[i] = bytes32(BlsGenerators.q - agg_at_z);

msm_bases[++i] = proofs[0];
msm_scalars[i] = bytes32(zs[0]);

msm_bases[++i] = proofs[1];
msm_scalars[i] = bytes32(BlsGenerators.mul_fr(r, zs[1]));

BLS.G1Point memory agg_acc = BLS.msm(msm_bases, msm_scalars);
BLS.G1Point memory acc_proof = BLS.add(proofs[0], BlsGenerators.g1_mul(proofs[1], bytes32(r)));
return verify_acc(agg_acc, acc_proof, tau_g2);
}

function verify(BLS.G1Point memory c, uint256 z, uint256 v, BLS.G1Point memory proof, BLS.G2Point memory tau_g2)
internal
view
returns (bool)
{
bytes32[] memory msm_scalars = new bytes32[](2);
BLS.G1Point[] memory msm_bases = new BLS.G1Point[](2);
msm_scalars[0] = bytes32(z);
msm_bases[0] = proof;
msm_scalars[1] = bytes32(BlsGenerators.q - v);
msm_bases[1] = BlsGenerators.G1();
BLS.G1Point memory acc = BLS.msm(msm_bases, msm_scalars);
acc = BLS.add(acc, c);
return verify_acc(acc, proof, tau_g2);
}

function verify_acc(BLS.G1Point memory acc, BLS.G1Point memory acc_proof, BLS.G2Point memory tau_g2)
internal
view
returns (bool)
{
return pairing2(acc, BlsGenerators.G2_NEG(), acc_proof, tau_g2);
}

function pairing2(
BLS.G1Point memory g1_1,
BLS.G2Point memory g2_1,
BLS.G1Point memory g1_2,
BLS.G2Point memory g2_2
) internal view returns (bool result) {
BLS.G1Point[] memory g1_points = new BLS.G1Point[](2);
BLS.G2Point[] memory g2_points = new BLS.G2Point[](2);
g1_points[0] = g1_1;
g2_points[0] = g2_1;
g1_points[1] = g1_2;
g2_points[1] = g2_2;
return BLS.pairing(g1_points, g2_points);
}
}
67 changes: 67 additions & 0 deletions evm-vrfier/contracts/src/Plonk.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
pragma solidity ^0.8.24;

import {BLS, Kzg} from "src/Kzg.sol";
import {Constraints} from "src/Constraints.sol";

contract Plonk {
// The trapdoor `tau` in G2, part of the standard KZG verification key.
BLS.G2Point tau_g2;

constructor(BLS.G2Point memory tau_g2_) {
tau_g2 = tau_g2_;
}

function verify_proof(
BLS.G1Point[] memory columns,
BLS.G1Point memory quotient,
uint256 z,
uint256[] memory columns_at_z,
uint256[] memory columns_at_zw,
BLS.G1Point memory kzg_proof_at_z,
BLS.G1Point memory kzg_proof_at_zw,
uint256[] memory nus
) public view returns (bool) {
uint256 k = columns.length;
require(columns_at_z.length == k);
require(columns_at_zw.length <= k);

BLS.G1Point[] memory polys = new BLS.G1Point[](k + 1);
for (uint256 i = 0; i < k; i++) {
polys[i] = columns[i];
}
polys[k] = quotient;

uint256[] memory evals_at_z = new uint256[](k + 1);
for (uint256 i = 0; i < k; i++) {
evals_at_z[i] = columns_at_z[i];
}
evals_at_z[k] = compute_quotient(columns_at_z, columns_at_zw, z);

BLS.G1Point[] memory kzg_proofs = new BLS.G1Point[](2);
kzg_proofs[0] = kzg_proof_at_z;
kzg_proofs[1] = kzg_proof_at_zw;
uint256[] memory zs = new uint256[](2);
zs[0] = z;
zs[1] = Constraints.mul(z, Constraints.w);
return Kzg.verify_plonk_kzg(polys, zs, evals_at_z, columns_at_zw, kzg_proofs, nus, tau_g2);
}

function compute_quotient(uint256[] memory columns_at_z1, uint256[] memory columns_at_z2, uint256 z)
internal
view
returns (uint256)
{
uint256 not_last = Constraints.not_last_row(z);
(uint256 cx, uint256 cy) = Constraints.cond_te_addition(
columns_at_z1[4],
columns_at_z1[0],
columns_at_z1[1],
columns_at_z1[2],
columns_at_z1[3],
columns_at_z2[0],
columns_at_z2[1],
not_last
);
return Constraints.quotient_at(Constraints.add(cx, cy), z); //TODO: alphas
}
}
93 changes: 0 additions & 93 deletions evm-vrfier/contracts/src/PlonkKzg.sol

This file was deleted.

Loading
Loading