WIP: reorg to allow for more curves

Current tests are failing because ECMUL is not a valid opcode in hardhat. Exploring alternatives.
This commit is contained in:
Eric Mastro 2022-06-08 15:15:05 +10:00
parent 98c2555036
commit 976ae66cab
No known key found for this signature in database
GPG Key ID: 141E3048D95A4E63
9 changed files with 207 additions and 137 deletions

View File

@ -1,9 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <=0.8.13;
import "./curves/Bn254Proofs.sol";
import "./ecc/verifiers/Bn254Verifier.sol";
import "./ecc/Verifier.sol";
contract Proofs {
using Bn254Verifier for Verifier.Proof;
uint256 private immutable period;
uint256 private immutable timeout;
uint8 private immutable downtime;
@ -131,8 +134,8 @@ contract Proofs {
return _isProofRequired(id, currentPeriod());
}
function _submitProof(bytes32 id, bytes calldata proof) internal {
require(proof.length > 0, "Invalid proof"); // TODO: replace by actual check
function _submitProof(bytes32 id, Verifier.Proof calldata proof) internal {
require(proof._verifyProof(), "Invalid proof");
require(!received[id][currentPeriod()], "Proof already submitted");
received[id][currentPeriod()] = true;
emit ProofSubmitted(id, proof);

View File

@ -86,7 +86,7 @@ contract Storage is Collateral, Marketplace, Proofs {
return _getPointer(id);
}
function submitProof(bytes32 contractId, bytes calldata proof) public {
function submitProof(bytes32 contractId, Verifier.Proof calldata proof) public {
_submitProof(contractId, proof);
}

View File

@ -2,47 +2,48 @@
pragma solidity >=0.8.0 <=0.8.13;
import "./curves/Bn254.sol";
import "./ecc/curves/Bn254.sol";
import "./ecc/Curve.sol";
contract TestBn254 {
using Bn254 for *;
struct VerifyingKey {
Bn254.G2Point A;
Bn254.G1Point B;
Bn254.G2Point C;
Bn254.G2Point gamma;
Bn254.G1Point gammaBeta1;
Bn254.G2Point gammaBeta2;
Bn254.G2Point Z;
Bn254.G1Point[] IC;
Curve.G2Point A;
Curve.G1Point B;
Curve.G2Point C;
Curve.G2Point gamma;
Curve.G1Point gammaBeta1;
Curve.G2Point gammaBeta2;
Curve.G2Point Z;
Curve.G1Point[] IC;
}
struct Proof {
Bn254.G1Point A;
Bn254.G1Point A_p;
Bn254.G2Point B;
Bn254.G1Point B_p;
Bn254.G1Point C;
Bn254.G1Point C_p;
Bn254.G1Point K;
Bn254.G1Point H;
Curve.G1Point A;
Curve.G1Point A_p;
Curve.G2Point B;
Curve.G1Point B_p;
Curve.G1Point C;
Curve.G1Point C_p;
Curve.G1Point K;
Curve.G1Point H;
}
function f() internal view returns (bool) {
Bn254.G1Point memory p1;
Bn254.G1Point memory p2;
function f() public view returns (bool) {
Curve.G1Point memory p1;
Curve.G1Point memory p2;
p1.X = 1; p1.Y = 2;
p2.X = 1; p2.Y = 2;
Bn254.G1Point memory explict_sum = Bn254.g1add(p1, p2);
Bn254.G1Point memory scalar_prod = Bn254.g1mul(p1, 2);
Curve.G1Point memory explict_sum = Bn254.g1add(p1, p2);
Curve.G1Point memory scalar_prod = Bn254.g1mul(p1, 2);
return (explict_sum.X == scalar_prod.X &&
explict_sum.Y == scalar_prod.Y);
}
function g() internal view returns (bool) {
Bn254.G1Point memory x = Bn254.g1add(Bn254.P1(), Bn254.g1neg(Bn254.P1()));
function g() public view returns (bool) {
Curve.G1Point memory x = Bn254.g1add(Bn254.P1(), Bn254.g1neg(Bn254.P1()));
// should be zero
return (x.X == 0 && x.Y == 0);
}
function testMul() internal view returns (bool) {
Bn254.G1Point memory p;
function testMul() public view returns (bool) {
Curve.G1Point memory p;
// @TODO The points here are reported to be not well-formed
p.X = 14125296762497065001182820090155008161146766663259912659363835465243039841726;
p.Y = 16229134936871442251132173501211935676986397196799085184804749187146857848057;
@ -51,15 +52,15 @@ contract TestBn254 {
p.X == 18256332256630856740336504687838346961237861778318632856900758565550522381207 &&
p.Y == 6976682127058094634733239494758371323697222088503263230319702770853579280803;
}
function pair() internal view returns (bool) {
Bn254.G2Point memory fiveTimesP2 = Bn254.G2Point(
function pair() public view returns (bool) {
Curve.G2Point memory fiveTimesP2 = Curve.G2Point(
[4540444681147253467785307942530223364530218361853237193970751657229138047649, 20954117799226682825035885491234530437475518021362091509513177301640194298072],
[11631839690097995216017572651900167465857396346217730511548857041925508482915, 21508930868448350162258892668132814424284302804699005394342512102884055673846]
);
// The prime p in the base field F_p for G1
uint p = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
Bn254.G1Point[] memory g1points = new Bn254.G1Point[](2);
Bn254.G2Point[] memory g2points = new Bn254.G2Point[](2);
Curve.G1Point[] memory g1points = new Curve.G1Point[](2);
Curve.G2Point[] memory g2points = new Curve.G2Point[](2);
// // check e(5 P1, P2)e(-P1, 5 P2) == 1
g1points[0] = Bn254.P1().g1mul(5);
g1points[1] = Bn254.P1();
@ -78,30 +79,30 @@ contract TestBn254 {
return true;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.A = Bn254.G2Point([0x209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7, 0x04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678], [0x2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d, 0x120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550]);
vk.B = Bn254.G1Point(0x2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc02, 0x03d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db84);
vk.C = Bn254.G2Point([0x2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb, 0x01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb3], [0x14a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713, 0x178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee24590]);
vk.gamma = Bn254.G2Point([0x25f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb1, 0x22acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d], [0x065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf68, 0x06d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb]);
vk.gammaBeta1 = Bn254.G1Point(0x15794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f21, 0x14db745c6780e9df549864cec19c2daf4531f6ec0c89cc1c7436cc4d8d300c6d);
vk.gammaBeta2 = Bn254.G2Point([0x1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e, 0x283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39], [0x140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e, 0x0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd4]);
vk.Z = Bn254.G2Point([0x217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac29, 0x0a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c], [0x26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a9855, 0x2fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d7]);
vk.IC = new Bn254.G1Point[](10);
vk.IC[0] = Bn254.G1Point(0x0aee46a7ea6e80a3675026dfa84019deee2a2dedb1bbe11d7fe124cb3efb4b5a, 0x044747b6e9176e13ede3a4dfd0d33ccca6321b9acd23bf3683a60adc0366ebaf);
vk.IC[1] = Bn254.G1Point(0x1e39e9f0f91fa7ff8047ffd90de08785777fe61c0e3434e728fce4cf35047ddc, 0x2e0b64d75ebfa86d7f8f8e08abbe2e7ae6e0a1c0b34d028f19fa56e9450527cb);
vk.IC[2] = Bn254.G1Point(0x1c36e713d4d54e3a9644dffca1fc524be4868f66572516025a61ca542539d43f, 0x042dcc4525b82dfb242b09cb21909d5c22643dcdbe98c4d082cc2877e96b24db);
vk.IC[3] = Bn254.G1Point(0x17d5d09b4146424bff7e6fb01487c477bbfcd0cdbbc92d5d6457aae0b6717cc5, 0x02b5636903efbf46db9235bbe74045d21c138897fda32e079040db1a16c1a7a1);
vk.IC[4] = Bn254.G1Point(0x0f103f14a584d4203c27c26155b2c955f8dfa816980b24ba824e1972d6486a5d, 0x0c4165133b9f5be17c804203af781bcf168da7386620479f9b885ecbcd27b17b);
vk.IC[5] = Bn254.G1Point(0x232063b584fb76c8d07995bee3a38fa7565405f3549c6a918ddaa90ab971e7f8, 0x2ac9b135a81d96425c92d02296322ad56ffb16299633233e4880f95aafa7fda7);
vk.IC[6] = Bn254.G1Point(0x09b54f111d3b2d1b2fe1ae9669b3db3d7bf93b70f00647e65c849275de6dc7fe, 0x18b2e77c63a3e400d6d1f1fbc6e1a1167bbca603d34d03edea231eb0ab7b14b4);
vk.IC[7] = Bn254.G1Point(0x0c54b42137b67cc268cbb53ac62b00ecead23984092b494a88befe58445a244a, 0x18e3723d37fae9262d58b548a0575f59d9c3266db7afb4d5739555837f6b8b3e);
vk.IC[8] = Bn254.G1Point(0x0a6de0e2240aa253f46ce0da883b61976e3588146e01c9d8976548c145fe6e4a, 0x04fbaa3a4aed4bb77f30ebb07a3ec1c7d77a7f2edd75636babfeff97b1ea686e);
vk.IC[9] = Bn254.G1Point(0x111e2e2a5f8828f80ddad08f9f74db56dac1cc16c1cb278036f79a84cf7a116f, 0x1d7d62e192b219b9808faa906c5ced871788f6339e8d91b83ac1343e20a16b30);
vk.A = Curve.G2Point([0x209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7, 0x04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678], [0x2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d, 0x120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550]);
vk.B = Curve.G1Point(0x2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc02, 0x03d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db84);
vk.C = Curve.G2Point([0x2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb, 0x01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb3], [0x14a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713, 0x178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee24590]);
vk.gamma = Curve.G2Point([0x25f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb1, 0x22acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d], [0x065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf68, 0x06d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb]);
vk.gammaBeta1 = Curve.G1Point(0x15794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f21, 0x14db745c6780e9df549864cec19c2daf4531f6ec0c89cc1c7436cc4d8d300c6d);
vk.gammaBeta2 = Curve.G2Point([0x1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e, 0x283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39], [0x140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e, 0x0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd4]);
vk.Z = Curve.G2Point([0x217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac29, 0x0a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c], [0x26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a9855, 0x2fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d7]);
vk.IC = new Curve.G1Point[](10);
vk.IC[0] = Curve.G1Point(0x0aee46a7ea6e80a3675026dfa84019deee2a2dedb1bbe11d7fe124cb3efb4b5a, 0x044747b6e9176e13ede3a4dfd0d33ccca6321b9acd23bf3683a60adc0366ebaf);
vk.IC[1] = Curve.G1Point(0x1e39e9f0f91fa7ff8047ffd90de08785777fe61c0e3434e728fce4cf35047ddc, 0x2e0b64d75ebfa86d7f8f8e08abbe2e7ae6e0a1c0b34d028f19fa56e9450527cb);
vk.IC[2] = Curve.G1Point(0x1c36e713d4d54e3a9644dffca1fc524be4868f66572516025a61ca542539d43f, 0x042dcc4525b82dfb242b09cb21909d5c22643dcdbe98c4d082cc2877e96b24db);
vk.IC[3] = Curve.G1Point(0x17d5d09b4146424bff7e6fb01487c477bbfcd0cdbbc92d5d6457aae0b6717cc5, 0x02b5636903efbf46db9235bbe74045d21c138897fda32e079040db1a16c1a7a1);
vk.IC[4] = Curve.G1Point(0x0f103f14a584d4203c27c26155b2c955f8dfa816980b24ba824e1972d6486a5d, 0x0c4165133b9f5be17c804203af781bcf168da7386620479f9b885ecbcd27b17b);
vk.IC[5] = Curve.G1Point(0x232063b584fb76c8d07995bee3a38fa7565405f3549c6a918ddaa90ab971e7f8, 0x2ac9b135a81d96425c92d02296322ad56ffb16299633233e4880f95aafa7fda7);
vk.IC[6] = Curve.G1Point(0x09b54f111d3b2d1b2fe1ae9669b3db3d7bf93b70f00647e65c849275de6dc7fe, 0x18b2e77c63a3e400d6d1f1fbc6e1a1167bbca603d34d03edea231eb0ab7b14b4);
vk.IC[7] = Curve.G1Point(0x0c54b42137b67cc268cbb53ac62b00ecead23984092b494a88befe58445a244a, 0x18e3723d37fae9262d58b548a0575f59d9c3266db7afb4d5739555837f6b8b3e);
vk.IC[8] = Curve.G1Point(0x0a6de0e2240aa253f46ce0da883b61976e3588146e01c9d8976548c145fe6e4a, 0x04fbaa3a4aed4bb77f30ebb07a3ec1c7d77a7f2edd75636babfeff97b1ea686e);
vk.IC[9] = Curve.G1Point(0x111e2e2a5f8828f80ddad08f9f74db56dac1cc16c1cb278036f79a84cf7a116f, 0x1d7d62e192b219b9808faa906c5ced871788f6339e8d91b83ac1343e20a16b30);
}
function verify(uint[] memory input, Proof memory proof) internal view returns (uint) {
VerifyingKey memory vk = verifyingKey();
require(input.length + 1 == vk.IC.length);
// Compute the linear combination vk_x
Bn254.G1Point memory vk_x = Bn254.G1Point(0, 0);
Curve.G1Point memory vk_x = Curve.G1Point(0, 0);
for (uint i = 0; i < input.length; i++)
vk_x = Bn254.g1add(vk_x, Bn254.g1mul(vk.IC[i + 1], input[i]));
vk_x = Bn254.g1add(vk_x, vk.IC[0]);
@ -124,16 +125,16 @@ contract TestBn254 {
function verifyTx() internal returns (bool r) {
uint[] memory input = new uint[](9);
Proof memory proof;
proof.A = Bn254.G1Point(12873740738727497448187997291915224677121726020054032516825496230827252793177, 21804419174137094775122804775419507726154084057848719988004616848382402162497);
proof.A_p = Bn254.G1Point(7742452358972543465462254569134860944739929848367563713587808717088650354556, 7324522103398787664095385319014038380128814213034709026832529060148225837366);
proof.B = Bn254.G2Point(
proof.A = Curve.G1Point(12873740738727497448187997291915224677121726020054032516825496230827252793177, 21804419174137094775122804775419507726154084057848719988004616848382402162497);
proof.A_p = Curve.G1Point(7742452358972543465462254569134860944739929848367563713587808717088650354556, 7324522103398787664095385319014038380128814213034709026832529060148225837366);
proof.B = Curve.G2Point(
[8176651290984905087450403379100573157708110416512446269839297438960217797614, 15588556568726919713003060429893850972163943674590384915350025440408631945055],
[15347511022514187557142999444367533883366476794364262773195059233657571533367, 4265071979090628150845437155927259896060451682253086069461962693761322642015]);
proof.B_p = Bn254.G1Point(2979746655438963305714517285593753729335852012083057917022078236006592638393, 6470627481646078059765266161088786576504622012540639992486470834383274712950);
proof.C = Bn254.G1Point(6851077925310461602867742977619883934042581405263014789956638244065803308498, 10336382210592135525880811046708757754106524561907815205241508542912494488506);
proof.C_p = Bn254.G1Point(12491625890066296859584468664467427202390981822868257437245835716136010795448, 13818492518017455361318553880921248537817650587494176379915981090396574171686);
proof.H = Bn254.G1Point(12091046215835229523641173286701717671667447745509192321596954139357866668225, 14446807589950902476683545679847436767890904443411534435294953056557941441758);
proof.K = Bn254.G1Point(21341087976609916409401737322664290631992568431163400450267978471171152600502, 2942165230690572858696920423896381470344658299915828986338281196715687693170);
proof.B_p = Curve.G1Point(2979746655438963305714517285593753729335852012083057917022078236006592638393, 6470627481646078059765266161088786576504622012540639992486470834383274712950);
proof.C = Curve.G1Point(6851077925310461602867742977619883934042581405263014789956638244065803308498, 10336382210592135525880811046708757754106524561907815205241508542912494488506);
proof.C_p = Curve.G1Point(12491625890066296859584468664467427202390981822868257437245835716136010795448, 13818492518017455361318553880921248537817650587494176379915981090396574171686);
proof.H = Curve.G1Point(12091046215835229523641173286701717671667447745509192321596954139357866668225, 14446807589950902476683545679847436767890904443411534435294953056557941441758);
proof.K = Curve.G1Point(21341087976609916409401737322664290631992568431163400450267978471171152600502, 2942165230690572858696920423896381470344658299915828986338281196715687693170);
input[0] = 13986731495506593864492662381614386532349950841221768152838255933892789078521;
input[1] = 622860516154313070522697309645122400675542217310916019527100517240519630053;
input[2] = 11094488463398718754251685950409355128550342438297986977413505294941943071569;

View File

@ -56,7 +56,7 @@ contract TestProofs is Proofs {
return _getPointer(id);
}
function submitProof(bytes32 id, bytes calldata proof) public {
function submitProof(bytes32 id, Verifier.Proof calldata proof) public {
_submitProof(id, proof);
}

16
contracts/ecc/Curve.sol Normal file
View File

@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <=0.8.13;
library Curve {
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
}

View File

@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <=0.8.13;
import "./Curve.sol";
library Verifier {
struct QElement {
int64 i;
uint256 v;
}
struct Proof {
// TODO: should `q` be bounded?
QElement[] q;
uint256[10] mus;
// sigma is probably only the x coordinate
// (https://github.com/supranational/blst#serialization-format)
Curve.G1Point sigma;
// TODO: should `u` be bounded?
Curve.G1Point[] u;
bytes name;
Curve.G2Point publicKey;
}
}

View File

@ -4,6 +4,8 @@
pragma solidity >=0.8.0 <=0.8.13;
import "../Curve.sol";
library Bn254 {
// p = p(u) = 36u^4 + 36u^3 + 24u^2 + 6u + 1
uint256 internal constant FIELD_ORDER =
@ -20,16 +22,16 @@ library Bn254 {
uint256 internal constant CURVE_A =
0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52;
struct G1Point {
uint256 X;
uint256 Y;
}
// struct Curve.G1Point {
// uint256 X;
// uint256 Y;
// }
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
// // Encoding of field elements is: X[0] * z + X[1]
// struct Curve.G2Point {
// uint256[2] X;
// uint256[2] Y;
// }
// (P+1) / 4
function A() internal pure returns (uint256) {
@ -49,11 +51,11 @@ library Bn254 {
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
function P1() internal pure returns (Curve.G1Point memory) {
return Curve.G1Point(1, 2);
}
function HashToPoint(uint256 s) internal view returns (G1Point memory g) {
function HashToPoint(uint256 s) internal view returns (Curve.G1Point memory g) {
uint256 beta = 0;
uint256 y = 0;
@ -65,7 +67,7 @@ library Bn254 {
// y^2 == beta
if (beta == mulmod(y, y, FIELD_ORDER)) {
return G1Point(x, y);
return Curve.G1Point(x, y);
}
x = addmod(x, 1, FIELD_ORDER);
@ -134,9 +136,9 @@ library Bn254 {
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
function P2() internal pure returns (Curve.G2Point memory) {
return
G2Point(
Curve.G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
@ -149,18 +151,18 @@ library Bn254 {
}
/// @return the negation of p, i.e. p.add(p.negate()) should be zero.
function g1neg(G1Point memory p) internal pure returns (G1Point memory) {
function g1neg(Curve.G1Point memory p) internal pure returns (Curve.G1Point memory) {
// The prime q in the base field F_q for G1
uint256 q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
return G1Point(p.X, q - (p.Y % q));
if (p.X == 0 && p.Y == 0) return Curve.G1Point(0, 0);
return Curve.G1Point(p.X, q - (p.Y % q));
}
/// @return r the sum of two points of G1
function g1add(G1Point memory p1, G1Point memory p2)
function g1add(Curve.G1Point memory p1, Curve.G1Point memory p2)
internal
view
returns (G1Point memory r)
returns (Curve.G1Point memory r)
{
uint256[4] memory input;
input[0] = p1.X;
@ -181,10 +183,10 @@ library Bn254 {
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.mul(1) and p.add(p) == p.mul(2) for all points p.
function g1mul(G1Point memory p, uint256 s)
function g1mul(Curve.G1Point memory p, uint256 s)
internal
view
returns (G1Point memory r)
returns (Curve.G1Point memory r)
{
uint256[3] memory input;
input[0] = p.X;
@ -206,7 +208,7 @@ library Bn254 {
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
/// return true.
function pairing(G1Point[] memory p1, G2Point[] memory p2)
function pairing(Curve.G1Point[] memory p1, Curve.G2Point[] memory p2)
internal
view
returns (bool)
@ -246,13 +248,13 @@ library Bn254 {
/// Convenience method for a pairing check for two pairs.
function pairingProd2(
G1Point memory a1,
G2Point memory a2,
G1Point memory b1,
G2Point memory b2
Curve.G1Point memory a1,
Curve.G2Point memory a2,
Curve.G1Point memory b1,
Curve.G2Point memory b2
) internal view returns (bool) {
G1Point[] memory p1 = new G1Point[](2);
G2Point[] memory p2 = new G2Point[](2);
Curve.G1Point[] memory p1 = new Curve.G1Point[](2);
Curve.G2Point[] memory p2 = new Curve.G2Point[](2);
p1[0] = a1;
p1[1] = b1;
p2[0] = a2;
@ -262,15 +264,15 @@ library Bn254 {
/// Convenience method for a pairing check for three pairs.
function pairingProd3(
G1Point memory a1,
G2Point memory a2,
G1Point memory b1,
G2Point memory b2,
G1Point memory c1,
G2Point memory c2
Curve.G1Point memory a1,
Curve.G2Point memory a2,
Curve.G1Point memory b1,
Curve.G2Point memory b2,
Curve.G1Point memory c1,
Curve.G2Point memory c2
) internal view returns (bool) {
G1Point[] memory p1 = new G1Point[](3);
G2Point[] memory p2 = new G2Point[](3);
Curve.G1Point[] memory p1 = new Curve.G1Point[](3);
Curve.G2Point[] memory p2 = new Curve.G2Point[](3);
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
@ -282,17 +284,17 @@ library Bn254 {
/// Convenience method for a pairing check for four pairs.
function pairingProd4(
G1Point memory a1,
G2Point memory a2,
G1Point memory b1,
G2Point memory b2,
G1Point memory c1,
G2Point memory c2,
G1Point memory d1,
G2Point memory d2
Curve.G1Point memory a1,
Curve.G2Point memory a2,
Curve.G1Point memory b1,
Curve.G2Point memory b2,
Curve.G1Point memory c1,
Curve.G2Point memory c2,
Curve.G1Point memory d1,
Curve.G2Point memory d2
) internal view returns (bool) {
G1Point[] memory p1 = new G1Point[](4);
G2Point[] memory p2 = new G2Point[](4);
Curve.G1Point[] memory p1 = new Curve.G1Point[](4);
Curve.G2Point[] memory p2 = new Curve.G2Point[](4);
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
@ -304,7 +306,7 @@ library Bn254 {
return pairing(p1, p2);
}
function isOnCurve(Bn254.G1Point memory g1) internal pure returns (bool) {
function isOnCurve(Curve.G1Point memory g1) internal pure returns (bool) {
uint256 aa = Bn254.A();
uint256 bb = Bn254.B();
uint256 pp = Bn254.P();

View File

@ -2,43 +2,28 @@
pragma solidity >=0.8.0 <=0.8.13;
import "./Bn254.sol";
import "../curves/Bn254.sol";
import "../Verifier.sol";
library Bn254Proofs {
struct QElement {
int64 i;
uint256 v;
}
library Bn254Verifier {
struct Proof {
// TODO: should `q` be bounded?
QElement[] q;
uint256[10] mus;
// sigma is probably only the x coordinate
// (https://github.com/supranational/blst#serialization-format)
Bn254.G1Point sigma;
// TODO: should `u` be bounded?
Bn254.G1Point[] u;
bytes name;
Bn254.G2Point publicKey;
}
function verifyProof(Proof memory proof) internal view returns (bool) {
function _verifyProof(Verifier.Proof memory proof) internal view returns (bool) {
// var first: blst_p1
// for qelem in q :
// var prod: blst_p1
// prod.blst_p1_mult(hashNameI(tau.t.name, qelem.I), qelem.V, 255)
// first.blst_p1_add_or_double(first, prod)
// doAssert(blst_p1_on_curve(first).bool)
Bn254.G1Point memory first;
Curve.G1Point memory first;
for (uint256 i = 0; i<proof.q.length; i++) {
QElement memory qelem = proof.q[i];
Verifier.QElement memory qelem = proof.q[i];
bytes32 namei = sha256(abi.encodePacked(proof.name, qelem.i));
// Step 4: arbitraty string to point and check if it is on curve
uint256 hPointX = uint256(namei);
Bn254.G1Point memory h = Bn254.HashToPoint(hPointX);
Curve.G1Point memory h = Bn254.HashToPoint(hPointX);
// TODO: Where does 255 get used???
Bn254.G1Point memory prod = Bn254.g1mul(h, uint256(qelem.v));
Curve.G1Point memory prod = Bn254.g1mul(h, uint256(qelem.v));
first = Bn254.g1add(first, prod);
require(Bn254.isOnCurve(first), "must be on Bn254 curve");
}
@ -49,18 +34,18 @@ library Bn254Proofs {
// prod.blst_p1_mult(us[j], mus[j], 255)
// second.blst_p1_add_or_double(second, prod)
// doAssert(blst_p1_on_curve(second).bool)
Bn254.G1Point[] memory us = proof.u;
Bn254.G1Point memory second;
Curve.G1Point[] memory us = proof.u;
Curve.G1Point memory second;
for (uint256 j = 0; j<us.length; j++) {
// TODO: Where does 255 get used???
Bn254.G1Point memory prod = Bn254.g1mul(us[j], proof.mus[j]);
Curve.G1Point memory prod = Bn254.g1mul(us[j], proof.mus[j]);
second = Bn254.g1add(second, prod);
require(Bn254.isOnCurve(second), "must be on Bn254 curve");
}
// var sum: blst_p1
// sum.blst_p1_add_or_double(first, second)
Bn254.G1Point memory sum = Bn254.g1add(first, second);
Curve.G1Point memory sum = Bn254.g1add(first, second);
// var g{.noInit.}: blst_p2
// g.blst_p2_from_affine(BLS12_381_G2)

38
test/Bn254.test.js Normal file
View File

@ -0,0 +1,38 @@
const { expect } = require("chai")
const { ethers } = require("hardhat")
const {
snapshot,
revert,
ensureMinimumBlockHeight,
currentTime,
advanceTime,
advanceTimeTo,
} = require("./evm")
const { periodic } = require("./time")
describe("Bn254", function () {
let bn254
beforeEach(async function () {
await snapshot()
await ensureMinimumBlockHeight(256)
const Bn254 = await ethers.getContractFactory("TestBn254")
bn254 = await Bn254.deploy()
})
afterEach(async function () {
await revert()
})
it("explicit sum and scalar prod are the same", async function () {
expect(await bn254.f()).to.be.true
})
it("adding point to negation of itself should be zero", async function () {
expect(await bn254.g()).to.be.true
})
it("multiplication along BN254 emits expected values", async function () {
expect(await bn254.testMul()).to.be.true
})
})