diff --git a/src/blocks/HyperKzg.sol b/src/blocks/HyperKzg.sol new file mode 100644 index 0000000..e6e1892 --- /dev/null +++ b/src/blocks/HyperKzg.sol @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.16; + +import "src/blocks/grumpkin/Bn256.sol"; +import "src/blocks/Pairing.sol"; +import "src/blocks/KeccakTranscript.sol"; + +library HyperKzg { + struct HyperKzgInput { + Bn256.Bn256AffinePoint[] pi_comms; + uint256[] R_x; + uint256[] pi_evals_0; + uint256[] pi_evals_1; + uint256[] pi_evals_2; + uint256 p_of_x; + uint256[] point; + Bn256.Bn256AffinePoint C; + Bn256.Bn256AffinePoint C_Q; + Bn256.Bn256AffinePoint C_H; + Bn256.Bn256AffinePoint vk_g; + Pairing.G2Point beta_h; + Pairing.G2Point h; + } + + 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]; + } + output[output.length - 1] = element; + return output; + } + + function insertPoint(Bn256.Bn256AffinePoint[] memory input, Bn256.Bn256AffinePoint memory point, uint256 index) + private + pure + returns (Bn256.Bn256AffinePoint[] memory) + { + require(index <= input.length, "unexpected index"); + + Bn256.Bn256AffinePoint[] memory output = new Bn256.Bn256AffinePoint[](input.length + 1); + for (uint256 i = 0; i < index; i++) { + output[i] = input[i]; + } + output[index] = point; + for (uint256 i = index + 1; i < output.length; i++) { + output[i] = input[i - 1]; + } + return output; + } + + function pi_polys_are_correct( + uint256[] memory pi_evals_0, + uint256[] memory pi_evals_1, + uint256[] memory pi_evals_2, + uint256[] memory point_in, + uint256 r, + uint256 p_of_x + ) 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"); + + uint256[] memory evals_0 = pushElement(pi_evals_0, p_of_x); + uint256[] memory evals_1 = pushElement(pi_evals_1, p_of_x); + uint256[] memory evals_2 = pushElement(pi_evals_2, p_of_x); + + // reverse order of points + uint256[] memory point = new uint256[](point_in.length); + for (uint256 index = 0; index < point.length; index++) { + point[point.length - index - 1] = point_in[index]; + } + + uint256 r_mul_2 = mulmod(2, r, Bn256.R_MOD); + + uint256 even; + uint256 odd; + uint256 left; + uint256 right; + uint256 tmp; + for (uint256 index = 0; index < point.length; index++) { + even = addmod(evals_0[index], evals_1[index], Bn256.R_MOD); + odd = addmod(evals_0[index], Bn256.negateScalar(evals_1[index]), Bn256.R_MOD); + tmp = mulmod(point[index], odd, Bn256.R_MOD); + right = addmod(1, Bn256.negateScalar(point[index]), Bn256.R_MOD); + right = mulmod(right, even, Bn256.R_MOD); + right = mulmod(right, r, Bn256.R_MOD); + right = addmod(right, tmp, Bn256.P_MOD); + + left = mulmod(evals_2[index + 1], r_mul_2, Bn256.R_MOD); + + if (left != right) { + return false; + } + } + return true; + } + + function compute_C_P(Bn256.Bn256AffinePoint[] memory pi_comms, Bn256.Bn256AffinePoint memory C, uint256 q) + private + returns (Bn256.Bn256AffinePoint memory) + { + Bn256.Bn256AffinePoint[] memory comms = insertPoint(pi_comms, C, 0); + + uint256[] memory q_degrees = new uint256[](comms.length); + q_degrees[0] = 1; + q_degrees[1] = q; + + for (uint256 i = 2; i < comms.length; i++) { + q_degrees[i] = mulmod(q_degrees[i - 1], q, Bn256.R_MOD); + } + return Bn256.multiScalarMul(comms, q_degrees); + } + + function compute_C_K( + HyperKzgInput memory input, + uint256 a, + uint256[] memory D_coeffs, + PolyLib.UniPoly memory R_x_poly, + Bn256.Bn256AffinePoint memory C_P + ) private returns (Bn256.Bn256AffinePoint memory) { + Bn256.Bn256AffinePoint memory tmp = Bn256.scalarMul(input.vk_g, PolyLib.evaluate(R_x_poly, a, Bn256.R_MOD)); + Bn256.Bn256AffinePoint memory C_K = + Bn256.scalarMul(input.C_Q, PolyLib.evaluate(PolyLib.UniPoly(D_coeffs), a, Bn256.R_MOD)); + C_K = Bn256.negate(Bn256.add(tmp, C_K)); + C_K = Bn256.add(C_P, C_K); + return C_K; + } + + function pairingCheckSuccessful(HyperKzgInput memory input, Bn256.Bn256AffinePoint memory C_K, uint256 a) + private + returns (bool) + { + /* + let pairing_inputs: Vec<(E::G1Affine, E::G2Prepared)> = vec![ + (C_H, vk.beta_h.into()), + ((C_H * (-a) - C_K).to_affine(), vk.h.into()), + ]; + */ + Pairing.G1Point memory g1_1 = Pairing.G1Point(input.C_H); + Pairing.G2Point memory g2_1 = input.beta_h; + + Pairing.G1Point memory g1_2 = + Pairing.G1Point(Bn256.add(Bn256.negate(C_K), Bn256.scalarMul(input.C_H, Bn256.negateScalar(a)))); + Pairing.G2Point memory g2_2 = input.h; + + return Pairing.pairingProd2(g1_1, g2_1, g1_2, g2_2); + } + + function verify(HyperKzgInput memory input, KeccakTranscriptLib.KeccakTranscript memory transcript) + public + returns (bool) + { + // b"c" in Rust + uint8[] memory label = new uint8[](1); + label[0] = 0x63; + + transcript = KeccakTranscriptLib.absorb(transcript, label, input.pi_comms); + uint256 r; + (transcript, r) = KeccakTranscriptLib.squeeze(transcript, ScalarFromUniformLib.curveBn256(), label); + + uint256[] memory u = new uint256[](3); + u[0] = r; + u[1] = Bn256.negateScalar(r); + u[2] = mulmod(r, r, Bn256.R_MOD); + + PolyLib.UniPoly memory R_x_poly = PolyLib.UniPoly(input.R_x); + + // b"v" in Rust + label[0] = 0x76; + transcript = KeccakTranscriptLib.absorb(transcript, label, input.pi_evals_0, input.pi_evals_1, input.pi_evals_2); + + // b"r" in Rust + label[0] = 0x72; + uint256 q; + (transcript, q) = KeccakTranscriptLib.squeeze(transcript, ScalarFromUniformLib.curveBn256(), label); + + PolyLib.UniPoly[3] memory evals = + [PolyLib.UniPoly(input.pi_evals_0), PolyLib.UniPoly(input.pi_evals_1), PolyLib.UniPoly(input.pi_evals_2)]; + for (uint256 i = 0; i < evals.length; i++) { + if (PolyLib.evaluate(R_x_poly, u[i], Bn256.R_MOD) != PolyLib.evaluate(evals[i], q, Bn256.R_MOD)) { + return false; + } + } + + if (!pi_polys_are_correct(input.pi_evals_0, input.pi_evals_1, input.pi_evals_2, input.point, r, input.p_of_x)) { + return false; + } + + Bn256.Bn256AffinePoint memory C_P = compute_C_P(input.pi_comms, input.C, q); + + // D = (x - r) * (x + r) * (x - r^2) = 1 * x^3 - r^2 * x^2 - r^2 * x + r^4 + uint256[] memory D_coeffs = new uint256[](4); + D_coeffs[0] = mulmod(u[2], u[2], Bn256.R_MOD); + D_coeffs[1] = Bn256.negateScalar(u[2]); + D_coeffs[2] = Bn256.negateScalar(u[2]); + D_coeffs[3] = 1; + + // b"C_Q" in Rust + label = new uint8[](3); + label[0] = 0x43; + label[1] = 0x5f; + label[2] = 0x51; + transcript = KeccakTranscriptLib.absorb(transcript, label, input.C_Q); + + // b"a" in Rust + label = new uint8[](1); + label[0] = 0x61; + uint256 a; + (transcript, a) = KeccakTranscriptLib.squeeze(transcript, ScalarFromUniformLib.curveBn256(), label); + + Bn256.Bn256AffinePoint memory C_K = compute_C_K(input, a, D_coeffs, R_x_poly, C_P); + + return pairingCheckSuccessful(input, C_K, a); + } +} diff --git a/src/blocks/IpaPcs.sol b/src/blocks/IpaPcs.sol index c82a221..e3a8924 100644 --- a/src/blocks/IpaPcs.sol +++ b/src/blocks/IpaPcs.sol @@ -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); @@ -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)); @@ -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; diff --git a/src/blocks/KeccakTranscript.sol b/src/blocks/KeccakTranscript.sol index 8962bc3..20aa572 100644 --- a/src/blocks/KeccakTranscript.sol +++ b/src/blocks/KeccakTranscript.sol @@ -1027,6 +1027,46 @@ library KeccakTranscriptLib { return absorb(keccak, label, input); } + function absorb( + KeccakTranscript memory keccak, + uint8[] memory label, + uint256[] memory inputs_0, + uint256[] memory inputs_1, + uint256[] memory inputs_2 + ) 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; + for (uint256 i = 0; i < inputs_0.length; i++) { + uint8[] memory input_bytes = scalarToBytes(inputs_0[i]); + + for (uint256 j = 0; j < 32; j++) { + input[input_index] = input_bytes[j]; + input_index++; + } + } + + for (uint256 i = 0; i < inputs_1.length; i++) { + uint8[] memory input_bytes = scalarToBytes(inputs_1[i]); + + for (uint256 j = 0; j < 32; j++) { + input[input_index] = input_bytes[j]; + input_index++; + } + } + + for (uint256 i = 0; i < inputs_2.length; i++) { + uint8[] memory input_bytes = scalarToBytes(inputs_2[i]); + + for (uint256 j = 0; j < 32; j++) { + input[input_index] = input_bytes[j]; + input_index++; + } + } + + return absorb(keccak, label, input); + } + /** * @notice Absorbs a univariate polynomial into the Keccak transcript. * @dev Converts the polynomial to bytes and uses the standard `absorb` function. @@ -1252,7 +1292,7 @@ library KeccakTranscriptLib { } // write byte indicating whether point is at infinity - if (Bn256.is_identity(point)) { + if (!Bn256.is_identity(point)) { output[index] = 0x00; } else { output[index] = 0x01; @@ -1270,6 +1310,7 @@ library KeccakTranscriptLib { */ function absorb(KeccakTranscript memory keccak, uint8[] memory label, Grumpkin.GrumpkinAffinePoint memory point) public + pure returns (KeccakTranscript memory) { uint8[] memory output = new uint8[](32 * 2 + 1); @@ -1286,7 +1327,7 @@ library KeccakTranscriptLib { } // write byte indicating whether point is at infinity - if (Grumpkin.is_identity(point)) { + if (!Grumpkin.is_identity(point)) { output[index] = 0x00; } else { output[index] = 0x01; @@ -1323,7 +1364,7 @@ library KeccakTranscriptLib { } // write byte indicating whether point is at infinity - if (Bn256.is_identity(points[j])) { + if (!Bn256.is_identity(points[j])) { output[index] = 0x00; } else { output[index] = 0x01; @@ -1346,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 diff --git a/src/blocks/Pairing.sol b/src/blocks/Pairing.sol new file mode 100644 index 0000000..c2dce40 --- /dev/null +++ b/src/blocks/Pairing.sol @@ -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); + } +} diff --git a/src/blocks/ZeromorphEngine.sol b/src/blocks/ZeromorphEngine.sol index 0f19a21..51d2e42 100644 --- a/src/blocks/ZeromorphEngine.sol +++ b/src/blocks/ZeromorphEngine.sol @@ -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 @@ -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); - } -} diff --git a/src/blocks/grumpkin/Grumpkin.sol b/src/blocks/grumpkin/Grumpkin.sol index ce51075..1850b6b 100644 --- a/src/blocks/grumpkin/Grumpkin.sol +++ b/src/blocks/grumpkin/Grumpkin.sol @@ -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"); diff --git a/test/hyperkzg.t.sol b/test/hyperkzg.t.sol new file mode 100644 index 0000000..639f00c --- /dev/null +++ b/test/hyperkzg.t.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.16; + +import "@std/Test.sol"; +import "src/blocks/KeccakTranscript.sol"; +import "src/blocks/grumpkin/Bn256.sol"; +import "src/blocks/HyperKzg.sol"; + +contract HyperKzgTest is Test { + function composeHyperKzgInput() private pure returns (HyperKzg.HyperKzgInput memory) { + Bn256.Bn256AffinePoint[] memory pi_comms = new Bn256.Bn256AffinePoint[](2); + pi_comms[0] = Bn256.Bn256AffinePoint( + 0x1e252582f77d12b3fbf9376aa756426e7c9c6496be4f60f35f5b6a09cd65b580, + 0x1f57963fa20b11863d2043784a3a18b2114fb88c1952b6678e50be94d0b80e06 + ); + pi_comms[1] = Bn256.Bn256AffinePoint( + 0x25a9384bbdb73227da1ddb26c8e7563efda3ed03561766e1ebdb0afa1b44ace2, + 0x2c167a83cd2abcef00126bd88f03047cbdcfab86eede65e27a26e0e022dfbe44 + ); + + uint256[] memory R_x = new uint256[](3); + R_x[0] = 0x0668744da4b2c836a526ef2fd7542a5235eb6641607226dc4abbc82b64575fc9; + R_x[1] = 0x2fd7691f3ffbddb1d736d3383ba404ea1a1c0614d57dad97643851a51b834b5a; + R_x[2] = 0x037fe8cabffa876afdeea56f06697e141a23180e57ec226273e196d574eb4b85; + + uint256[] memory pi_evals_0 = new uint256[](3); + pi_evals_0[0] = 0x0c7736e33a1001b108e7a3ac40d072ed01af99ffb87fa2d5ed9750600253ad5a; + pi_evals_0[1] = 0x124b64189008472130026f55b6ddc63268636603c10c966a74339d933c7261df; + pi_evals_0[2] = 0x165b65c6cf5ed06ba20bd24fac16b88da1e9c5dd6901eec8ea888cd9cdda95e9; + + uint256[] memory pi_evals_1 = new uint256[](3); + pi_evals_1[0] = 0x1143360fd32e3d1e6c28544694b073e1549863be33d5cf0bd7df1cfa187f0300; + pi_evals_1[1] = 0x0eeef019ff0cc2b286f6daf143597325d803ab337fc1527a610746a912e7cbcc; + pi_evals_1[2] = 0x1a08e8ac11d2cfbe16447366d56a9fcf864a226b10b781c8595968ba22256a8a; + + uint256[] memory pi_evals_2 = new uint256[](3); + pi_evals_2[0] = 0x0137e8ed95aeb25bdd6f419220919937b9a20b304f5b811e84de9759dfdfa98c; + pi_evals_2[1] = 0x1e2ee91698c880a7659a7a822645cdb89a9e88ede8e2a15c3557842cfae39a93; + pi_evals_2[2] = 0x20a23f9e734d84352ef257f9ab6cdbb664f884c2414b38a5681237b6689d909c; + + uint256 p_of_x = 0x0000000000000000000000000000000000000000000000000000000000000039; + + uint256[] memory point = new uint256[](3); + point[0] = 0x0000000000000000000000000000000000000000000000000000000000000004; + point[1] = 0x0000000000000000000000000000000000000000000000000000000000000003; + point[2] = 0x0000000000000000000000000000000000000000000000000000000000000008; + + Bn256.Bn256AffinePoint memory C = Bn256.Bn256AffinePoint( + 0x2217f0ebf964dd979d11a0ad218290dcd70cf9e82d7b20c779fc97e8328f8512, + 0x0dd40f5b93890e2d683b84c06ed37b0fb3982d83df771ab0e7593a930f6ff666 + ); + Bn256.Bn256AffinePoint memory C_Q = Bn256.Bn256AffinePoint( + 0x17fa7dd4c9f33daf159191c6286eb0feca19233f87a72b61a4fb67cf8125f1ac, + 0x210cf9d424ae9e2d49f513dfcf15d914fca1168518c72a1c28e5ac25ac311473 + ); + Bn256.Bn256AffinePoint memory C_H = Bn256.Bn256AffinePoint( + 0x1ad1228340addaff3338e1a3cbf13b12d06f6e1cdee371362d4f7e391a9e7016, + 0x1ec571fa0118a7bc56c260559d9b0b7a4ef65cd0be79450362744ca539e3b7ce + ); + + Bn256.Bn256AffinePoint memory vk_g = Bn256.Bn256AffinePoint( + 0x0fc4701ef297cf49eb0c93df917d8546a35f048f4250ef99fd0fdc50d1848acc, + 0x0e639233f85f7f00b4ad1c99f19236a8fb918ed9a052e86b7ca07575d478e500 + ); + + Pairing.G2Point memory beta_h = Pairing.G2Point( + [ + 0x0bb659fbdbc9452452df8b156239350ac7111a21c815356dc1abfc1a5b9d9134, + 0x01c61ba933e55911edcd07161657ea81bbbe15ff3489d16268108ebee888b66b + ], + [ + 0x009eb4def1cfcf0020557a0fb66341ea45959df5e262d5bfcdebbfa9ed35ca5a, + 0x0e3b956418672742a67e1c980f13e934d8e755af02f8c2fcb63e18ad6a6b6ab4 + ] + ); + + Pairing.G2Point memory h = Pairing.G2Point( + [ + 0x0bd636a3af7014b4d9b117242da8a2163a31e0fe77249cc5daa7e9ba0cb4fadb, + 0x2a14219918143cff7b915de597c9eb6d94fb18db74799a82d09c988f1dc2f67e + ], + [ + 0x2bcfeeca3782c18f03413d57d31d9a0e02e8059ff5829befa14edcf9f4c1b6d4, + 0x2e0e806bfe80d792ee6c2ef78c11188db5f6b6d0f85bd46fa706316138f7fd0d + ] + ); + + return HyperKzg.HyperKzgInput( + pi_comms, R_x, pi_evals_0, pi_evals_1, pi_evals_2, p_of_x, point, C, C_Q, C_H, vk_g, beta_h, h + ); + } + + function testHyperKzgVerification() public { + HyperKzg.HyperKzgInput memory input = composeHyperKzgInput(); + KeccakTranscriptLib.KeccakTranscript memory transcript = getTranscript(); + assertTrue(HyperKzg.verify(input, transcript)); + } + + function getTranscript() public pure returns (KeccakTranscriptLib.KeccakTranscript memory) { + // b"TestEval" in Rust + uint8[] memory label = new uint8[](8); + label[0] = 0x54; + label[1] = 0x65; + label[2] = 0x73; + label[3] = 0x74; + label[4] = 0x45; + label[5] = 0x76; + label[6] = 0x61; + label[7] = 0x6c; + + KeccakTranscriptLib.KeccakTranscript memory keccak_transcript = KeccakTranscriptLib.instantiate(label); + return keccak_transcript; + } +} diff --git a/test/keccak-transcript-tests.t.sol b/test/keccak-transcript-tests.t.sol index 156eed9..2c94abf 100644 --- a/test/keccak-transcript-tests.t.sol +++ b/test/keccak-transcript-tests.t.sol @@ -517,4 +517,465 @@ contract KeccakTranscriptContractTest is Test { (transcript, r) = KeccakTranscriptLib.squeeze(transcript, ScalarFromUniformLib.curveGrumpkin(), label); assertEq(r, 0x1744e670b565ff687a3d35ddb3bd3c800b65d3297f59747846e2076f2da92655); } + + function testKeccakTranscriptHyperKzgComputations() public { + // b"TestEval" in Rust + uint8[] memory label = new uint8[](8); + label[0] = 0x54; + label[1] = 0x65; + label[2] = 0x73; + label[3] = 0x74; + label[4] = 0x45; + label[5] = 0x76; + label[6] = 0x61; + label[7] = 0x6c; + KeccakTranscriptLib.KeccakTranscript memory transcript = KeccakTranscriptLib.instantiate(label); + + // b"c" in Rust + label = new uint8[](1); + label[0] = 0x63; + + uint8[] memory pi_comms_bytes = new uint8[](130); + pi_comms_bytes[0] = 0x80; + pi_comms_bytes[1] = 0xb5; + pi_comms_bytes[2] = 0x65; + pi_comms_bytes[3] = 0xcd; + pi_comms_bytes[4] = 0x09; + pi_comms_bytes[5] = 0x6a; + pi_comms_bytes[6] = 0x5b; + pi_comms_bytes[7] = 0x5f; + pi_comms_bytes[8] = 0xf3; + pi_comms_bytes[9] = 0x60; + pi_comms_bytes[10] = 0x4f; + pi_comms_bytes[11] = 0xbe; + pi_comms_bytes[12] = 0x96; + pi_comms_bytes[13] = 0x64; + pi_comms_bytes[14] = 0x9c; + pi_comms_bytes[15] = 0x7c; + pi_comms_bytes[16] = 0x6e; + pi_comms_bytes[17] = 0x42; + pi_comms_bytes[18] = 0x56; + pi_comms_bytes[19] = 0xa7; + pi_comms_bytes[20] = 0x6a; + pi_comms_bytes[21] = 0x37; + pi_comms_bytes[22] = 0xf9; + pi_comms_bytes[23] = 0xfb; + pi_comms_bytes[24] = 0xb3; + pi_comms_bytes[25] = 0x12; + pi_comms_bytes[26] = 0x7d; + pi_comms_bytes[27] = 0xf7; + pi_comms_bytes[28] = 0x82; + pi_comms_bytes[29] = 0x25; + pi_comms_bytes[30] = 0x25; + pi_comms_bytes[31] = 0x1e; + pi_comms_bytes[32] = 0x06; + pi_comms_bytes[33] = 0x0e; + pi_comms_bytes[34] = 0xb8; + pi_comms_bytes[35] = 0xd0; + pi_comms_bytes[36] = 0x94; + pi_comms_bytes[37] = 0xbe; + pi_comms_bytes[38] = 0x50; + pi_comms_bytes[39] = 0x8e; + pi_comms_bytes[40] = 0x67; + pi_comms_bytes[41] = 0xb6; + pi_comms_bytes[42] = 0x52; + pi_comms_bytes[43] = 0x19; + pi_comms_bytes[44] = 0x8c; + pi_comms_bytes[45] = 0xb8; + pi_comms_bytes[46] = 0x4f; + pi_comms_bytes[47] = 0x11; + pi_comms_bytes[48] = 0xb2; + pi_comms_bytes[49] = 0x18; + pi_comms_bytes[50] = 0x3a; + pi_comms_bytes[51] = 0x4a; + pi_comms_bytes[52] = 0x78; + pi_comms_bytes[53] = 0x43; + pi_comms_bytes[54] = 0x20; + pi_comms_bytes[55] = 0x3d; + pi_comms_bytes[56] = 0x86; + pi_comms_bytes[57] = 0x11; + pi_comms_bytes[58] = 0x0b; + pi_comms_bytes[59] = 0xa2; + pi_comms_bytes[60] = 0x3f; + pi_comms_bytes[61] = 0x96; + pi_comms_bytes[62] = 0x57; + pi_comms_bytes[63] = 0x1f; + pi_comms_bytes[64] = 0x00; + pi_comms_bytes[65] = 0xe2; + pi_comms_bytes[66] = 0xac; + pi_comms_bytes[67] = 0x44; + pi_comms_bytes[68] = 0x1b; + pi_comms_bytes[69] = 0xfa; + pi_comms_bytes[70] = 0x0a; + pi_comms_bytes[71] = 0xdb; + pi_comms_bytes[72] = 0xeb; + pi_comms_bytes[73] = 0xe1; + pi_comms_bytes[74] = 0x66; + pi_comms_bytes[75] = 0x17; + pi_comms_bytes[76] = 0x56; + pi_comms_bytes[77] = 0x03; + pi_comms_bytes[78] = 0xed; + pi_comms_bytes[79] = 0xa3; + pi_comms_bytes[80] = 0xfd; + pi_comms_bytes[81] = 0x3e; + pi_comms_bytes[82] = 0x56; + pi_comms_bytes[83] = 0xe7; + pi_comms_bytes[84] = 0xc8; + pi_comms_bytes[85] = 0x26; + pi_comms_bytes[86] = 0xdb; + pi_comms_bytes[87] = 0x1d; + pi_comms_bytes[88] = 0xda; + pi_comms_bytes[89] = 0x27; + pi_comms_bytes[90] = 0x32; + pi_comms_bytes[91] = 0xb7; + pi_comms_bytes[92] = 0xbd; + pi_comms_bytes[93] = 0x4b; + pi_comms_bytes[94] = 0x38; + pi_comms_bytes[95] = 0xa9; + pi_comms_bytes[96] = 0x25; + pi_comms_bytes[97] = 0x44; + pi_comms_bytes[98] = 0xbe; + pi_comms_bytes[99] = 0xdf; + pi_comms_bytes[100] = 0x22; + pi_comms_bytes[101] = 0xe0; + pi_comms_bytes[102] = 0xe0; + pi_comms_bytes[103] = 0x26; + pi_comms_bytes[104] = 0x7a; + pi_comms_bytes[105] = 0xe2; + pi_comms_bytes[106] = 0x65; + pi_comms_bytes[107] = 0xde; + pi_comms_bytes[108] = 0xee; + pi_comms_bytes[109] = 0x86; + pi_comms_bytes[110] = 0xab; + pi_comms_bytes[111] = 0xcf; + pi_comms_bytes[112] = 0xbd; + pi_comms_bytes[113] = 0x7c; + pi_comms_bytes[114] = 0x04; + pi_comms_bytes[115] = 0x03; + pi_comms_bytes[116] = 0x8f; + pi_comms_bytes[117] = 0xd8; + pi_comms_bytes[118] = 0x6b; + pi_comms_bytes[119] = 0x12; + pi_comms_bytes[120] = 0x00; + pi_comms_bytes[121] = 0xef; + pi_comms_bytes[122] = 0xbc; + pi_comms_bytes[123] = 0x2a; + pi_comms_bytes[124] = 0xcd; + pi_comms_bytes[125] = 0x83; + pi_comms_bytes[126] = 0x7a; + pi_comms_bytes[127] = 0x16; + pi_comms_bytes[128] = 0x2c; + pi_comms_bytes[129] = 0x00; + + transcript = KeccakTranscriptLib.absorb(transcript, label, pi_comms_bytes); + + uint256 r; + (transcript, r) = KeccakTranscriptLib.squeeze(transcript, ScalarFromUniformLib.curveBn256(), label); + + uint256 r_expected = 0x16773788bb333f3d56ea6fd6e4446170588c0f1bf5ff49802c0fa3e47e8f101a; + assertEq(r_expected, r); + + // b"v" in Rust + label[0] = 0x76; + + uint8[] memory pi_evals_bytes = new uint8[](288); + pi_evals_bytes[0] = 0x5a; + pi_evals_bytes[1] = 0xad; + pi_evals_bytes[2] = 0x53; + pi_evals_bytes[3] = 0x02; + pi_evals_bytes[4] = 0x60; + pi_evals_bytes[5] = 0x50; + pi_evals_bytes[6] = 0x97; + pi_evals_bytes[7] = 0xed; + pi_evals_bytes[8] = 0xd5; + pi_evals_bytes[9] = 0xa2; + pi_evals_bytes[10] = 0x7f; + pi_evals_bytes[11] = 0xb8; + pi_evals_bytes[12] = 0xff; + pi_evals_bytes[13] = 0x99; + pi_evals_bytes[14] = 0xaf; + pi_evals_bytes[15] = 0x01; + pi_evals_bytes[16] = 0xed; + pi_evals_bytes[17] = 0x72; + pi_evals_bytes[18] = 0xd0; + pi_evals_bytes[19] = 0x40; + pi_evals_bytes[20] = 0xac; + pi_evals_bytes[21] = 0xa3; + pi_evals_bytes[22] = 0xe7; + pi_evals_bytes[23] = 0x08; + pi_evals_bytes[24] = 0xb1; + pi_evals_bytes[25] = 0x01; + pi_evals_bytes[26] = 0x10; + pi_evals_bytes[27] = 0x3a; + pi_evals_bytes[28] = 0xe3; + pi_evals_bytes[29] = 0x36; + pi_evals_bytes[30] = 0x77; + pi_evals_bytes[31] = 0x0c; + pi_evals_bytes[32] = 0xdf; + pi_evals_bytes[33] = 0x61; + pi_evals_bytes[34] = 0x72; + pi_evals_bytes[35] = 0x3c; + pi_evals_bytes[36] = 0x93; + pi_evals_bytes[37] = 0x9d; + pi_evals_bytes[38] = 0x33; + pi_evals_bytes[39] = 0x74; + pi_evals_bytes[40] = 0x6a; + pi_evals_bytes[41] = 0x96; + pi_evals_bytes[42] = 0x0c; + pi_evals_bytes[43] = 0xc1; + pi_evals_bytes[44] = 0x03; + pi_evals_bytes[45] = 0x66; + pi_evals_bytes[46] = 0x63; + pi_evals_bytes[47] = 0x68; + pi_evals_bytes[48] = 0x32; + pi_evals_bytes[49] = 0xc6; + pi_evals_bytes[50] = 0xdd; + pi_evals_bytes[51] = 0xb6; + pi_evals_bytes[52] = 0x55; + pi_evals_bytes[53] = 0x6f; + pi_evals_bytes[54] = 0x02; + pi_evals_bytes[55] = 0x30; + pi_evals_bytes[56] = 0x21; + pi_evals_bytes[57] = 0x47; + pi_evals_bytes[58] = 0x08; + pi_evals_bytes[59] = 0x90; + pi_evals_bytes[60] = 0x18; + pi_evals_bytes[61] = 0x64; + pi_evals_bytes[62] = 0x4b; + pi_evals_bytes[63] = 0x12; + pi_evals_bytes[64] = 0xe9; + pi_evals_bytes[65] = 0x95; + pi_evals_bytes[66] = 0xda; + pi_evals_bytes[67] = 0xcd; + pi_evals_bytes[68] = 0xd9; + pi_evals_bytes[69] = 0x8c; + pi_evals_bytes[70] = 0x88; + pi_evals_bytes[71] = 0xea; + pi_evals_bytes[72] = 0xc8; + pi_evals_bytes[73] = 0xee; + pi_evals_bytes[74] = 0x01; + pi_evals_bytes[75] = 0x69; + pi_evals_bytes[76] = 0xdd; + pi_evals_bytes[77] = 0xc5; + pi_evals_bytes[78] = 0xe9; + pi_evals_bytes[79] = 0xa1; + pi_evals_bytes[80] = 0x8d; + pi_evals_bytes[81] = 0xb8; + pi_evals_bytes[82] = 0x16; + pi_evals_bytes[83] = 0xac; + pi_evals_bytes[84] = 0x4f; + pi_evals_bytes[85] = 0xd2; + pi_evals_bytes[86] = 0x0b; + pi_evals_bytes[87] = 0xa2; + pi_evals_bytes[88] = 0x6b; + pi_evals_bytes[89] = 0xd0; + pi_evals_bytes[90] = 0x5e; + pi_evals_bytes[91] = 0xcf; + pi_evals_bytes[92] = 0xc6; + pi_evals_bytes[93] = 0x65; + pi_evals_bytes[94] = 0x5b; + pi_evals_bytes[95] = 0x16; + pi_evals_bytes[96] = 0x00; + pi_evals_bytes[97] = 0x03; + pi_evals_bytes[98] = 0x7f; + pi_evals_bytes[99] = 0x18; + pi_evals_bytes[100] = 0xfa; + pi_evals_bytes[101] = 0x1c; + pi_evals_bytes[102] = 0xdf; + pi_evals_bytes[103] = 0xd7; + pi_evals_bytes[104] = 0x0b; + pi_evals_bytes[105] = 0xcf; + pi_evals_bytes[106] = 0xd5; + pi_evals_bytes[107] = 0x33; + pi_evals_bytes[108] = 0xbe; + pi_evals_bytes[109] = 0x63; + pi_evals_bytes[110] = 0x98; + pi_evals_bytes[111] = 0x54; + pi_evals_bytes[112] = 0xe1; + pi_evals_bytes[113] = 0x73; + pi_evals_bytes[114] = 0xb0; + pi_evals_bytes[115] = 0x94; + pi_evals_bytes[116] = 0x46; + pi_evals_bytes[117] = 0x54; + pi_evals_bytes[118] = 0x28; + pi_evals_bytes[119] = 0x6c; + pi_evals_bytes[120] = 0x1e; + pi_evals_bytes[121] = 0x3d; + pi_evals_bytes[122] = 0x2e; + pi_evals_bytes[123] = 0xd3; + pi_evals_bytes[124] = 0x0f; + pi_evals_bytes[125] = 0x36; + pi_evals_bytes[126] = 0x43; + pi_evals_bytes[127] = 0x11; + pi_evals_bytes[128] = 0xcc; + pi_evals_bytes[129] = 0xcb; + pi_evals_bytes[130] = 0xe7; + pi_evals_bytes[131] = 0x12; + pi_evals_bytes[132] = 0xa9; + pi_evals_bytes[133] = 0x46; + pi_evals_bytes[134] = 0x07; + pi_evals_bytes[135] = 0x61; + pi_evals_bytes[136] = 0x7a; + pi_evals_bytes[137] = 0x52; + pi_evals_bytes[138] = 0xc1; + pi_evals_bytes[139] = 0x7f; + pi_evals_bytes[140] = 0x33; + pi_evals_bytes[141] = 0xab; + pi_evals_bytes[142] = 0x03; + pi_evals_bytes[143] = 0xd8; + pi_evals_bytes[144] = 0x25; + pi_evals_bytes[145] = 0x73; + pi_evals_bytes[146] = 0x59; + pi_evals_bytes[147] = 0x43; + pi_evals_bytes[148] = 0xf1; + pi_evals_bytes[149] = 0xda; + pi_evals_bytes[150] = 0xf6; + pi_evals_bytes[151] = 0x86; + pi_evals_bytes[152] = 0xb2; + pi_evals_bytes[153] = 0xc2; + pi_evals_bytes[154] = 0x0c; + pi_evals_bytes[155] = 0xff; + pi_evals_bytes[156] = 0x19; + pi_evals_bytes[157] = 0xf0; + pi_evals_bytes[158] = 0xee; + pi_evals_bytes[159] = 0x0e; + pi_evals_bytes[160] = 0x8a; + pi_evals_bytes[161] = 0x6a; + pi_evals_bytes[162] = 0x25; + pi_evals_bytes[163] = 0x22; + pi_evals_bytes[164] = 0xba; + pi_evals_bytes[165] = 0x68; + pi_evals_bytes[166] = 0x59; + pi_evals_bytes[167] = 0x59; + pi_evals_bytes[168] = 0xc8; + pi_evals_bytes[169] = 0x81; + pi_evals_bytes[170] = 0xb7; + pi_evals_bytes[171] = 0x10; + pi_evals_bytes[172] = 0x6b; + pi_evals_bytes[173] = 0x22; + pi_evals_bytes[174] = 0x4a; + pi_evals_bytes[175] = 0x86; + pi_evals_bytes[176] = 0xcf; + pi_evals_bytes[177] = 0x9f; + pi_evals_bytes[178] = 0x6a; + pi_evals_bytes[179] = 0xd5; + pi_evals_bytes[180] = 0x66; + pi_evals_bytes[181] = 0x73; + pi_evals_bytes[182] = 0x44; + pi_evals_bytes[183] = 0x16; + pi_evals_bytes[184] = 0xbe; + pi_evals_bytes[185] = 0xcf; + pi_evals_bytes[186] = 0xd2; + pi_evals_bytes[187] = 0x11; + pi_evals_bytes[188] = 0xac; + pi_evals_bytes[189] = 0xe8; + pi_evals_bytes[190] = 0x08; + pi_evals_bytes[191] = 0x1a; + pi_evals_bytes[192] = 0x8c; + pi_evals_bytes[193] = 0xa9; + pi_evals_bytes[194] = 0xdf; + pi_evals_bytes[195] = 0xdf; + pi_evals_bytes[196] = 0x59; + pi_evals_bytes[197] = 0x97; + pi_evals_bytes[198] = 0xde; + pi_evals_bytes[199] = 0x84; + pi_evals_bytes[200] = 0x1e; + pi_evals_bytes[201] = 0x81; + pi_evals_bytes[202] = 0x5b; + pi_evals_bytes[203] = 0x4f; + pi_evals_bytes[204] = 0x30; + pi_evals_bytes[205] = 0x0b; + pi_evals_bytes[206] = 0xa2; + pi_evals_bytes[207] = 0xb9; + pi_evals_bytes[208] = 0x37; + pi_evals_bytes[209] = 0x99; + pi_evals_bytes[210] = 0x91; + pi_evals_bytes[211] = 0x20; + pi_evals_bytes[212] = 0x92; + pi_evals_bytes[213] = 0x41; + pi_evals_bytes[214] = 0x6f; + pi_evals_bytes[215] = 0xdd; + pi_evals_bytes[216] = 0x5b; + pi_evals_bytes[217] = 0xb2; + pi_evals_bytes[218] = 0xae; + pi_evals_bytes[219] = 0x95; + pi_evals_bytes[220] = 0xed; + pi_evals_bytes[221] = 0xe8; + pi_evals_bytes[222] = 0x37; + pi_evals_bytes[223] = 0x01; + pi_evals_bytes[224] = 0x93; + pi_evals_bytes[225] = 0x9a; + pi_evals_bytes[226] = 0xe3; + pi_evals_bytes[227] = 0xfa; + pi_evals_bytes[228] = 0x2c; + pi_evals_bytes[229] = 0x84; + pi_evals_bytes[230] = 0x57; + pi_evals_bytes[231] = 0x35; + pi_evals_bytes[232] = 0x5c; + pi_evals_bytes[233] = 0xa1; + pi_evals_bytes[234] = 0xe2; + pi_evals_bytes[235] = 0xe8; + pi_evals_bytes[236] = 0xed; + pi_evals_bytes[237] = 0x88; + pi_evals_bytes[238] = 0x9e; + pi_evals_bytes[239] = 0x9a; + pi_evals_bytes[240] = 0xb8; + pi_evals_bytes[241] = 0xcd; + pi_evals_bytes[242] = 0x45; + pi_evals_bytes[243] = 0x26; + pi_evals_bytes[244] = 0x82; + pi_evals_bytes[245] = 0x7a; + pi_evals_bytes[246] = 0x9a; + pi_evals_bytes[247] = 0x65; + pi_evals_bytes[248] = 0xa7; + pi_evals_bytes[249] = 0x80; + pi_evals_bytes[250] = 0xc8; + pi_evals_bytes[251] = 0x98; + pi_evals_bytes[252] = 0x16; + pi_evals_bytes[253] = 0xe9; + pi_evals_bytes[254] = 0x2e; + pi_evals_bytes[255] = 0x1e; + pi_evals_bytes[256] = 0x9c; + pi_evals_bytes[257] = 0x90; + pi_evals_bytes[258] = 0x9d; + pi_evals_bytes[259] = 0x68; + pi_evals_bytes[260] = 0xb6; + pi_evals_bytes[261] = 0x37; + pi_evals_bytes[262] = 0x12; + pi_evals_bytes[263] = 0x68; + pi_evals_bytes[264] = 0xa5; + pi_evals_bytes[265] = 0x38; + pi_evals_bytes[266] = 0x4b; + pi_evals_bytes[267] = 0x41; + pi_evals_bytes[268] = 0xc2; + pi_evals_bytes[269] = 0x84; + pi_evals_bytes[270] = 0xf8; + pi_evals_bytes[271] = 0x64; + pi_evals_bytes[272] = 0xb6; + pi_evals_bytes[273] = 0xdb; + pi_evals_bytes[274] = 0x6c; + pi_evals_bytes[275] = 0xab; + pi_evals_bytes[276] = 0xf9; + pi_evals_bytes[277] = 0x57; + pi_evals_bytes[278] = 0xf2; + pi_evals_bytes[279] = 0x2e; + pi_evals_bytes[280] = 0x35; + pi_evals_bytes[281] = 0x84; + pi_evals_bytes[282] = 0x4d; + pi_evals_bytes[283] = 0x73; + pi_evals_bytes[284] = 0x9e; + pi_evals_bytes[285] = 0x3f; + pi_evals_bytes[286] = 0xa2; + pi_evals_bytes[287] = 0x20; + + transcript = KeccakTranscriptLib.absorb(transcript, label, pi_evals_bytes); + + // b"r" in Rust + label[0] = 0x72; + uint256 q; + (transcript, q) = KeccakTranscriptLib.squeeze(transcript, ScalarFromUniformLib.curveBn256(), label); + + uint256 q_expected = 0x273c998898d8b87c2df1925e91b2ac91abb5f3c933fdd6817b08c13a97c05148; + assertEq(q_expected, q); + } } diff --git a/test/zeromorph.t.sol b/test/zeromorph.t.sol index 9ad14f5..a099277 100644 --- a/test/zeromorph.t.sol +++ b/test/zeromorph.t.sol @@ -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);