Skip to content

Commit

Permalink
chore: Export Pairing verification library
Browse files Browse the repository at this point in the history
  • Loading branch information
storojs72 committed Mar 5, 2024
1 parent 914b039 commit 39d94dd
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 136 deletions.
4 changes: 3 additions & 1 deletion src/blocks/IpaPcs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ library InnerProductArgument {

function compute_P_hat_right(P_hat_right_input memory input)
private
view
returns (Grumpkin.GrumpkinAffinePoint memory)
{
uint256[] memory s = new uint256[](input.n);
Expand Down Expand Up @@ -194,6 +195,7 @@ library InnerProductArgument {

function compute_P_hat_left(IpaInputGrumpkin memory input, R memory r_vec, Grumpkin.GrumpkinAffinePoint memory ck_c)
private
view
returns (Grumpkin.GrumpkinAffinePoint memory)
{
Grumpkin.GrumpkinAffinePoint memory P = Grumpkin.add(input.commitment, Grumpkin.scalarMul(ck_c, input.eval));
Expand Down Expand Up @@ -232,7 +234,7 @@ library InnerProductArgument {
uint256 a_hat,
Grumpkin.GrumpkinAffinePoint memory ck_hat,
Grumpkin.GrumpkinAffinePoint memory ck_c
) private returns (Grumpkin.GrumpkinAffinePoint memory) {
) private view returns (Grumpkin.GrumpkinAffinePoint memory) {
Grumpkin.GrumpkinAffinePoint[] memory bases = new Grumpkin.GrumpkinAffinePoint[](2);
bases[0] = ck_hat;
bases[1] = ck_c;
Expand Down
4 changes: 2 additions & 2 deletions src/blocks/KeccakTranscript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1033,7 +1033,7 @@ library KeccakTranscriptLib {
uint256[] memory inputs_0,
uint256[] memory inputs_1,
uint256[] memory inputs_2
) public returns (KeccakTranscript memory) {
) public pure returns (KeccakTranscript memory) {
uint8[] memory input = new uint8[](32 * inputs_0.length + 32 * inputs_1.length + 32 * inputs_2.length);

uint256 input_index = 0;
Expand Down Expand Up @@ -1387,7 +1387,7 @@ library KeccakTranscriptLib {
KeccakTranscript memory keccak,
uint8[] memory label,
InnerProductArgument.InstanceGrumpkin memory ipa_input
) public returns (KeccakTranscript memory) {
) public pure returns (KeccakTranscript memory) {
uint256 output_length = 0;
output_length += 32 * 2 + 1; // comm_a_vec
// we don't write b_vec to transcript according to reference implementation
Expand Down
75 changes: 75 additions & 0 deletions src/blocks/Pairing.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.16;

import "src/blocks/grumpkin/Bn256.sol";

/**
* @title Pairing Library
* @notice Provides functionalities for elliptic curve pairing operations, specifically for BN256 curve. Based on:
* https://gist.github.com/chriseth/f9be9d9391efc5beb9704255a8e2989d
* @dev This library is essential for cryptographic operations that require pairing checks.
*/
library Pairing {
// Represents a point on G1 (first group of BN256 curve).
struct G1Point {
Bn256.Bn256AffinePoint inner;
}
// Represents a point on G2 (second group of BN256 curve).

struct G2Point {
uint256[2] X;
uint256[2] Y;
}

/**
* @notice Computes the pairing check of two sets of points.
* @param p1 Array of G1 points.
* @param p2 Array of G2 points.
* @return True if the pairing check passes, false otherwise.
* @dev For example pairing([P1(), P1().negate()], [P2(), P2()]) should
* return true.
*/
function pairing(G1Point[] memory p1, G2Point[] memory p2) internal returns (bool) {
require(p1.length == p2.length);
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].inner.x;
input[i * 6 + 1] = p1[i].inner.y;
// To be compatible with Rust, it is necessary to reverse the field element encoding
input[i * 6 + 2] = p2[i].X[1];
input[i * 6 + 3] = p2[i].X[0];
input[i * 6 + 4] = p2[i].Y[1];
input[i * 6 + 5] = p2[i].Y[0];
}
uint256[1] memory out;
assembly {
let success := call(sub(gas(), 2000), 8, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
switch success
case 0 { revert(0, 0) }
}
return out[0] != 0;
}

/**
* @notice Computes the product of pairings for two pairs of points.
* @param a1 The first G1 point in the first pair.
* @param a2 The first G2 point in the first pair.
* @param b1 The second G1 point in the second pair.
* @param b2 The second G2 point in the second pair.
* @return True if the product of pairings check passes, false otherwise.
*/
function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2)
internal
returns (bool)
{
G1Point[] memory p1 = new G1Point[](2);
G2Point[] memory p2 = new G2Point[](2);
p1[0] = a1;
p1[1] = b1;
p2[0] = a2;
p2[1] = b2;
return pairing(p1, p2);
}
}
126 changes: 1 addition & 125 deletions src/blocks/ZeromorphEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.16;

import "@std/Test.sol";
import "src/blocks/grumpkin/Bn256.sol";
import "src/blocks/Pairing.sol";

/**
* @title Zeromorph Library
Expand Down Expand Up @@ -157,128 +158,3 @@ library Zeromorph {
return output;
}
}

/**
* @title Pairing Library
* @notice Provides functionalities for elliptic curve pairing operations, specifically for BN256 curve. Based on:
* https://gist.github.com/chriseth/f9be9d9391efc5beb9704255a8e2989d
* @dev This library is essential for cryptographic operations that require pairing checks.
*/
library Pairing {
// Represents a point on G1 (first group of BN256 curve).
struct G1Point {
Bn256.Bn256AffinePoint inner;
}
// Represents a point on G2 (second group of BN256 curve).

struct G2Point {
uint256[2] X;
uint256[2] Y;
}

/**
* @notice Provides a predefined G1 point.
* @return A predefined point on G1.
*/
function P1() internal pure returns (G1Point memory) {
return G1Point(Bn256.Bn256AffinePoint(1, 2));
}

/**
* @notice Provides a predefined G2 point.
* @return A predefined point on G2.
*/
function P2() internal pure returns (G2Point memory) {
return G2Point(
[
10857046999023057135944570762232829481370756359578518086990519993285655852781,
11559732032986387107991004021392285783925812861821192530917403151452391805634
],
[
8495653923123431417604973247489272438418190587263600148770280649306958101930,
4082367875863433681332203403145435568316851327593401208105741076214120093531
]
);
}

/**
* @notice Negates a G1 point.
* @param p The G1 point to negate.
* @return The negated G1 point.
*/
function negate(G1Point memory p) internal pure returns (G1Point memory) {
return G1Point(Bn256.negate(p.inner));
}

/**
* @notice Multiplies a G1 point with a scalar.
* @param p The G1 point to multiply.
* @param s The scalar to multiply with.
* @return The result of the multiplication.
*/
function mul(G1Point memory p, uint256 s) internal returns (G1Point memory) {
return G1Point(Bn256.scalarMul(p.inner, s));
}

/**
* @notice Adds two G1 points.
* @param p1 The first G1 point.
* @param p2 The second G1 point.
* @return The sum of the two G1 points.
*/
function add(G1Point memory p1, G1Point memory p2) internal returns (G1Point memory) {
return G1Point(Bn256.add(p1.inner, p2.inner));
}

/**
* @notice Computes the pairing check of two sets of points.
* @param p1 Array of G1 points.
* @param p2 Array of G2 points.
* @return True if the pairing check passes, false otherwise.
* @dev For example pairing([P1(), P1().negate()], [P2(), P2()]) should
* return true.
*/
function pairing(G1Point[] memory p1, G2Point[] memory p2) internal returns (bool) {
require(p1.length == p2.length);
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].inner.x;
input[i * 6 + 1] = p1[i].inner.y;
// To be compatible with Rust, it is necessary to reverse the field element encoding
input[i * 6 + 2] = p2[i].X[1];
input[i * 6 + 3] = p2[i].X[0];
input[i * 6 + 4] = p2[i].Y[1];
input[i * 6 + 5] = p2[i].Y[0];
}
uint256[1] memory out;
assembly {
let success := call(sub(gas(), 2000), 8, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
switch success
case 0 { revert(0, 0) }
}
return out[0] != 0;
}

/**
* @notice Computes the product of pairings for two pairs of points.
* @param a1 The first G1 point in the first pair.
* @param a2 The first G2 point in the first pair.
* @param b1 The second G1 point in the second pair.
* @param b2 The second G2 point in the second pair.
* @return True if the product of pairings check passes, false otherwise.
*/
function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2)
internal
returns (bool)
{
G1Point[] memory p1 = new G1Point[](2);
G2Point[] memory p2 = new G2Point[](2);
p1[0] = a1;
p1[1] = b1;
p2[0] = a2;
p2[1] = b2;
return pairing(p1, p2);
}
}
1 change: 1 addition & 0 deletions src/blocks/grumpkin/Grumpkin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ library Grumpkin {

function multiScalarMul(GrumpkinAffinePoint[] memory bases, uint256[] memory scalars)
public
view
returns (GrumpkinAffinePoint memory r)
{
require(scalars.length == bases.length, "MSM error: length does not match");
Expand Down
9 changes: 5 additions & 4 deletions test/hyperkzg.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import "@std/Test.sol";
import "src/blocks/KeccakTranscript.sol";
import "src/blocks/grumpkin/Bn256.sol";
import "src/Utilities.sol";
import "src/blocks/ZeromorphEngine.sol";
import "src/blocks/Pairing.sol";

contract HyperKzgTest is Test {
function pushElement(uint256[] memory input, uint256 element) private returns (uint256[] memory) {
function pushElement(uint256[] memory input, uint256 element) private pure returns (uint256[] memory) {
uint256[] memory output = new uint256[](input.length + 1);
for (uint256 i = 0; i < input.length; i++) {
output[i] = input[i];
Expand All @@ -19,6 +19,7 @@ contract HyperKzgTest is Test {

function insertPoint(Bn256.Bn256AffinePoint[] memory input, Bn256.Bn256AffinePoint memory point, uint256 index)
private
pure
returns (Bn256.Bn256AffinePoint[] memory)
{
require(index <= input.length, "unexpected index");
Expand All @@ -41,7 +42,7 @@ contract HyperKzgTest is Test {
uint256[] memory point_in,
uint256 r,
uint256 p_of_x
) private returns (bool) {
) private pure returns (bool) {
require(pi_evals_0.length == point_in.length, "unexpected length of pi_evals_0");
require(pi_evals_1.length == point_in.length, "unexpected length of pi_evals_1");
require(pi_evals_2.length == point_in.length, "unexpected length of pi_evals_2");
Expand Down Expand Up @@ -148,7 +149,7 @@ contract HyperKzgTest is Test {
Pairing.G2Point h;
}

function composeHyperKzgInput() private returns (HyperKzgInput memory) {
function composeHyperKzgInput() private pure returns (HyperKzgInput memory) {
Bn256.Bn256AffinePoint[] memory pi_comms = new Bn256.Bn256AffinePoint[](2);
pi_comms[0] = Bn256.Bn256AffinePoint(
0x1e252582f77d12b3fbf9376aa756426e7c9c6496be4f60f35f5b6a09cd65b580,
Expand Down
17 changes: 13 additions & 4 deletions test/zeromorph.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@ import "src/blocks/KeccakTranscript.sol";

contract ZeromorphContract is Test {
function testPairingUsage() public {
Pairing.G1Point memory g1_0 = Pairing.P1();
Pairing.G2Point memory g2_0 = Pairing.P2();
Pairing.G1Point memory g1_0 = Pairing.G1Point(Bn256.Bn256AffinePoint(1, 2));
Pairing.G2Point memory g2_0 = Pairing.G2Point(
[
10857046999023057135944570762232829481370756359578518086990519993285655852781,
11559732032986387107991004021392285783925812861821192530917403151452391805634
],
[
8495653923123431417604973247489272438418190587263600148770280649306958101930,
4082367875863433681332203403145435568316851327593401208105741076214120093531
]
);

Pairing.G1Point memory g1_1 = Pairing.negate(Pairing.P1());
Pairing.G2Point memory g2_1 = Pairing.P2();
Pairing.G1Point memory g1_1 = Pairing.G1Point(Bn256.negate(Bn256.Bn256AffinePoint(1, 2)));
Pairing.G2Point memory g2_1 = g2_0;

bool pairingResult = Pairing.pairingProd2(g1_0, g2_0, g1_1, g2_1);
assert(pairingResult);
Expand Down

0 comments on commit 39d94dd

Please sign in to comment.