aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-10-09 17:09:20 +0800
committerchriseth <chris@ethereum.org>2017-10-09 17:09:20 +0800
commit9ee619c9bba5cdbabfa9d587a0c726d1eaae9be9 (patch)
tree51e9dbdc5312c13397b9e4e07165eec4ad3f0ce6
parent6f832cacde44ba02c663ce2d90a381b567ec3e2c (diff)
downloaddexon-solidity-9ee619c9bba5cdbabfa9d587a0c726d1eaae9be9.tar.gz
dexon-solidity-9ee619c9bba5cdbabfa9d587a0c726d1eaae9be9.tar.zst
dexon-solidity-9ee619c9bba5cdbabfa9d587a0c726d1eaae9be9.zip
Snarks test using Byzantium precompiles
* Snark tests. * Verifying routine. * Example proof. * Update precompiled positions to Byzantium ruleset.
-rw-r--r--test/RPCSession.cpp5
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp301
2 files changed, 305 insertions, 1 deletions
diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp
index 768c8c4b..72b26453 100644
--- a/test/RPCSession.cpp
+++ b/test/RPCSession.cpp
@@ -236,7 +236,10 @@ void RPCSession::test_setChainParams(vector<string> const& _accounts)
"0000000000000000000000000000000000000001": { "wei": "1", "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
"0000000000000000000000000000000000000002": { "wei": "1", "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
"0000000000000000000000000000000000000003": { "wei": "1", "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
- "0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } }
+ "0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
+ "0000000000000000000000000000000000000006": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_add", "linear": { "base": 15, "word": 3 } } },
+ "0000000000000000000000000000000000000007": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_mul", "linear": { "base": 15, "word": 3 } } },
+ "0000000000000000000000000000000000000008": { "wei": "1", "precompiled": { "name": "alt_bn128_pairing_product", "linear": { "base": 15, "word": 3 } } }
}
}
)";
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 35916ec7..ac77a7e1 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -10176,6 +10176,307 @@ BOOST_AUTO_TEST_CASE(address_overload_resolution)
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(5)));
}
+BOOST_AUTO_TEST_CASE(snark)
+{
+ char const* sourceCode = R"(
+ library Pairing {
+ struct G1Point {
+ uint X;
+ uint Y;
+ }
+ // Encoding of field elements is: X[0] * z + X[1]
+ struct G2Point {
+ uint[2] X;
+ uint[2] Y;
+ }
+
+ /// @return the generator of G1
+ function P1() internal returns (G1Point) {
+ return G1Point(1, 2);
+ }
+
+ /// @return the generator of G2
+ function P2() internal returns (G2Point) {
+ return G2Point(
+ [11559732032986387107991004021392285783925812861821192530917403151452391805634,
+ 10857046999023057135944570762232829481370756359578518086990519993285655852781],
+ [4082367875863433681332203403145435568316851327593401208105741076214120093531,
+ 8495653923123431417604973247489272438418190587263600148770280649306958101930]
+ );
+ }
+
+ /// @return the negation of p, i.e. p.add(p.negate()) should be zero.
+ function negate(G1Point p) internal returns (G1Point) {
+ // The prime q in the base field F_q for G1
+ uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
+ if (p.X == 0 && p.Y == 0)
+ return G1Point(0, 0);
+ return G1Point(p.X, q - (p.Y % q));
+ }
+
+ /// @return the sum of two points of G1
+ function add(G1Point p1, G1Point p2) internal returns (G1Point r) {
+ uint[4] memory input;
+ input[0] = p1.X;
+ input[1] = p1.Y;
+ input[2] = p2.X;
+ input[3] = p2.Y;
+ bool success;
+ assembly {
+ success := call(sub(gas, 2000), 6, 0, input, 0xc0, r, 0x60)
+ // Use "invalid" to make gas estimation work
+ switch success case 0 { invalid() }
+ }
+ require(success);
+ }
+
+ /// @return 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 mul(G1Point p, uint s) internal returns (G1Point r) {
+ uint[3] memory input;
+ input[0] = p.X;
+ input[1] = p.Y;
+ input[2] = s;
+ bool success;
+ assembly {
+ success := call(sub(gas, 2000), 7, 0, input, 0x80, r, 0x60)
+ // Use "invalid" to make gas estimation work
+ switch success case 0 { invalid() }
+ }
+ require(success);
+ }
+
+ /// @return the result of computing the pairing check
+ /// 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[] p1, G2Point[] p2) internal returns (bool) {
+ require(p1.length == p2.length);
+ uint elements = p1.length;
+ uint inputSize = p1.length * 6;
+ uint[] memory input = new uint[](inputSize);
+ for (uint i = 0; i < elements; i++)
+ {
+ input[i * 6 + 0] = p1[i].X;
+ input[i * 6 + 1] = p1[i].Y;
+ input[i * 6 + 2] = p2[i].X[0];
+ input[i * 6 + 3] = p2[i].X[1];
+ input[i * 6 + 4] = p2[i].Y[0];
+ input[i * 6 + 5] = p2[i].Y[1];
+ }
+ uint[1] memory out;
+ bool success;
+ assembly {
+ success := call(sub(gas, 2000), 8, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
+ // Use "invalid" to make gas estimation work
+ switch success case 0 { invalid() }
+ }
+ require(success);
+ return out[0] != 0;
+ }
+ function pairingProd2(G1Point a1, G2Point a2, G1Point b1, G2Point 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);
+ }
+ function pairingProd3(
+ G1Point a1, G2Point a2,
+ G1Point b1, G2Point b2,
+ G1Point c1, G2Point c2
+ ) internal returns (bool) {
+ G1Point[] memory p1 = new G1Point[](3);
+ G2Point[] memory p2 = new G2Point[](3);
+ p1[0] = a1;
+ p1[1] = b1;
+ p1[2] = c1;
+ p2[0] = a2;
+ p2[1] = b2;
+ p2[2] = c2;
+ return pairing(p1, p2);
+ }
+ function pairingProd4(
+ G1Point a1, G2Point a2,
+ G1Point b1, G2Point b2,
+ G1Point c1, G2Point c2,
+ G1Point d1, G2Point d2
+ ) internal returns (bool) {
+ G1Point[] memory p1 = new G1Point[](4);
+ G2Point[] memory p2 = new G2Point[](4);
+ p1[0] = a1;
+ p1[1] = b1;
+ p1[2] = c1;
+ p1[3] = d1;
+ p2[0] = a2;
+ p2[1] = b2;
+ p2[2] = c2;
+ p2[3] = d2;
+ return pairing(p1, p2);
+ }
+ }
+
+ contract Test {
+ using Pairing for *;
+ struct VerifyingKey {
+ Pairing.G2Point A;
+ Pairing.G1Point B;
+ Pairing.G2Point C;
+ Pairing.G2Point gamma;
+ Pairing.G1Point gammaBeta1;
+ Pairing.G2Point gammaBeta2;
+ Pairing.G2Point Z;
+ Pairing.G1Point[] IC;
+ }
+ struct Proof {
+ Pairing.G1Point A;
+ Pairing.G1Point A_p;
+ Pairing.G2Point B;
+ Pairing.G1Point B_p;
+ Pairing.G1Point C;
+ Pairing.G1Point C_p;
+ Pairing.G1Point K;
+ Pairing.G1Point H;
+ }
+ function f() returns (bool) {
+ Pairing.G1Point memory p1;
+ Pairing.G1Point memory p2;
+ p1.X = 1; p1.Y = 2;
+ p2.X = 1; p2.Y = 2;
+ var explict_sum = Pairing.add(p1, p2);
+ var scalar_prod = Pairing.mul(p1, 2);
+ return (explict_sum.X == scalar_prod.X &&
+ explict_sum.Y == scalar_prod.Y);
+ }
+ function g() returns (bool) {
+ Pairing.G1Point memory x = Pairing.add(Pairing.P1(), Pairing.negate(Pairing.P1()));
+ // should be zero
+ return (x.X == 0 && x.Y == 0);
+ }
+ function testMul() returns (bool) {
+ Pairing.G1Point memory p;
+ // @TODO The points here are reported to be not well-formed
+ p.X = 14125296762497065001182820090155008161146766663259912659363835465243039841726;
+ p.Y = 16229134936871442251132173501211935676986397196799085184804749187146857848057;
+ p = Pairing.mul(p, 13986731495506593864492662381614386532349950841221768152838255933892789078521);
+ return
+ p.X == 18256332256630856740336504687838346961237861778318632856900758565550522381207 &&
+ p.Y == 6976682127058094634733239494758371323697222088503263230319702770853579280803;
+ }
+ function pair() returns (bool) {
+ Pairing.G2Point memory fiveTimesP2 = Pairing.G2Point(
+ [4540444681147253467785307942530223364530218361853237193970751657229138047649, 20954117799226682825035885491234530437475518021362091509513177301640194298072],
+ [11631839690097995216017572651900167465857396346217730511548857041925508482915, 21508930868448350162258892668132814424284302804699005394342512102884055673846]
+ );
+ // The prime p in the base field F_p for G1
+ uint p = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
+ Pairing.G1Point[] memory g1points = new Pairing.G1Point[](2);
+ Pairing.G2Point[] memory g2points = new Pairing.G2Point[](2);
+ // check e(5 P1, P2)e(-P1, 5 P2) == 1
+ g1points[0] = Pairing.P1().mul(5);
+ g1points[1] = Pairing.P1().negate();
+ g2points[0] = Pairing.P2();
+ g2points[1] = fiveTimesP2;
+ if (!Pairing.pairing(g1points, g2points))
+ return false;
+ // check e(P1, P2)e(-P1, P2) == 1
+ g1points[0] = Pairing.P1();
+ g1points[1] = Pairing.P1();
+ g1points[1].Y = p - g1points[1].Y;
+ g2points[0] = Pairing.P2();
+ g2points[1] = Pairing.P2();
+ if (!Pairing.pairing(g1points, g2points))
+ return false;
+ return true;
+ }
+ function verifyingKey() internal returns (VerifyingKey vk) {
+ vk.A = Pairing.G2Point([0x209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7, 0x04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678], [0x2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d, 0x120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550]);
+ vk.B = Pairing.G1Point(0x2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc02, 0x03d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db84);
+ vk.C = Pairing.G2Point([0x2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb, 0x01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb3], [0x14a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713, 0x178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee24590]);
+ vk.gamma = Pairing.G2Point([0x25f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb1, 0x22acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d], [0x065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf68, 0x06d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb]);
+ vk.gammaBeta1 = Pairing.G1Point(0x15794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f21, 0x14db745c6780e9df549864cec19c2daf4531f6ec0c89cc1c7436cc4d8d300c6d);
+ vk.gammaBeta2 = Pairing.G2Point([0x1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e, 0x283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39], [0x140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e, 0x0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd4]);
+ vk.Z = Pairing.G2Point([0x217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac29, 0x0a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c], [0x26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a9855, 0x2fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d7]);
+ vk.IC = new Pairing.G1Point[](10);
+ vk.IC[0] = Pairing.G1Point(0x0aee46a7ea6e80a3675026dfa84019deee2a2dedb1bbe11d7fe124cb3efb4b5a, 0x044747b6e9176e13ede3a4dfd0d33ccca6321b9acd23bf3683a60adc0366ebaf);
+ vk.IC[1] = Pairing.G1Point(0x1e39e9f0f91fa7ff8047ffd90de08785777fe61c0e3434e728fce4cf35047ddc, 0x2e0b64d75ebfa86d7f8f8e08abbe2e7ae6e0a1c0b34d028f19fa56e9450527cb);
+ vk.IC[2] = Pairing.G1Point(0x1c36e713d4d54e3a9644dffca1fc524be4868f66572516025a61ca542539d43f, 0x042dcc4525b82dfb242b09cb21909d5c22643dcdbe98c4d082cc2877e96b24db);
+ vk.IC[3] = Pairing.G1Point(0x17d5d09b4146424bff7e6fb01487c477bbfcd0cdbbc92d5d6457aae0b6717cc5, 0x02b5636903efbf46db9235bbe74045d21c138897fda32e079040db1a16c1a7a1);
+ vk.IC[4] = Pairing.G1Point(0x0f103f14a584d4203c27c26155b2c955f8dfa816980b24ba824e1972d6486a5d, 0x0c4165133b9f5be17c804203af781bcf168da7386620479f9b885ecbcd27b17b);
+ vk.IC[5] = Pairing.G1Point(0x232063b584fb76c8d07995bee3a38fa7565405f3549c6a918ddaa90ab971e7f8, 0x2ac9b135a81d96425c92d02296322ad56ffb16299633233e4880f95aafa7fda7);
+ vk.IC[6] = Pairing.G1Point(0x09b54f111d3b2d1b2fe1ae9669b3db3d7bf93b70f00647e65c849275de6dc7fe, 0x18b2e77c63a3e400d6d1f1fbc6e1a1167bbca603d34d03edea231eb0ab7b14b4);
+ vk.IC[7] = Pairing.G1Point(0x0c54b42137b67cc268cbb53ac62b00ecead23984092b494a88befe58445a244a, 0x18e3723d37fae9262d58b548a0575f59d9c3266db7afb4d5739555837f6b8b3e);
+ vk.IC[8] = Pairing.G1Point(0x0a6de0e2240aa253f46ce0da883b61976e3588146e01c9d8976548c145fe6e4a, 0x04fbaa3a4aed4bb77f30ebb07a3ec1c7d77a7f2edd75636babfeff97b1ea686e);
+ vk.IC[9] = Pairing.G1Point(0x111e2e2a5f8828f80ddad08f9f74db56dac1cc16c1cb278036f79a84cf7a116f, 0x1d7d62e192b219b9808faa906c5ced871788f6339e8d91b83ac1343e20a16b30);
+ }
+ function verify(uint[] input, Proof proof) internal returns (uint) {
+ VerifyingKey memory vk = verifyingKey();
+ require(input.length + 1 == vk.IC.length);
+ // Compute the linear combination vk_x
+ Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
+ for (uint i = 0; i < input.length; i++)
+ vk_x = Pairing.add(vk_x, Pairing.mul(vk.IC[i + 1], input[i]));
+ vk_x = Pairing.add(vk_x, vk.IC[0]);
+ if (!Pairing.pairingProd2(proof.A, vk.A, Pairing.negate(proof.A_p), Pairing.P2())) return 1;
+ if (!Pairing.pairingProd2(vk.B, proof.B, Pairing.negate(proof.B_p), Pairing.P2())) return 2;
+ if (!Pairing.pairingProd2(proof.C, vk.C, Pairing.negate(proof.C_p), Pairing.P2())) return 3;
+ if (!Pairing.pairingProd3(
+ proof.K, vk.gamma,
+ Pairing.negate(Pairing.add(vk_x, Pairing.add(proof.A, proof.C))), vk.gammaBeta2,
+ Pairing.negate(vk.gammaBeta1), proof.B
+ )) return 4;
+ if (!Pairing.pairingProd3(
+ Pairing.add(vk_x, proof.A), proof.B,
+ Pairing.negate(proof.H), vk.Z,
+ Pairing.negate(proof.C), Pairing.P2()
+ )) return 5;
+ return 0;
+ }
+ event Verified(string);
+ function verifyTx() returns (bool) {
+ uint[] memory input = new uint[](9);
+ Proof memory proof;
+ proof.A = Pairing.G1Point(12873740738727497448187997291915224677121726020054032516825496230827252793177, 21804419174137094775122804775419507726154084057848719988004616848382402162497);
+ proof.A_p = Pairing.G1Point(7742452358972543465462254569134860944739929848367563713587808717088650354556, 7324522103398787664095385319014038380128814213034709026832529060148225837366);
+ proof.B = Pairing.G2Point(
+ [8176651290984905087450403379100573157708110416512446269839297438960217797614, 15588556568726919713003060429893850972163943674590384915350025440408631945055],
+ [15347511022514187557142999444367533883366476794364262773195059233657571533367, 4265071979090628150845437155927259896060451682253086069461962693761322642015]);
+ proof.B_p = Pairing.G1Point(2979746655438963305714517285593753729335852012083057917022078236006592638393, 6470627481646078059765266161088786576504622012540639992486470834383274712950);
+ proof.C = Pairing.G1Point(6851077925310461602867742977619883934042581405263014789956638244065803308498, 10336382210592135525880811046708757754106524561907815205241508542912494488506);
+ proof.C_p = Pairing.G1Point(12491625890066296859584468664467427202390981822868257437245835716136010795448, 13818492518017455361318553880921248537817650587494176379915981090396574171686);
+ proof.H = Pairing.G1Point(12091046215835229523641173286701717671667447745509192321596954139357866668225, 14446807589950902476683545679847436767890904443411534435294953056557941441758);
+ proof.K = Pairing.G1Point(21341087976609916409401737322664290631992568431163400450267978471171152600502, 2942165230690572858696920423896381470344658299915828986338281196715687693170);
+ input[0] = 13986731495506593864492662381614386532349950841221768152838255933892789078521;
+ input[1] = 622860516154313070522697309645122400675542217310916019527100517240519630053;
+ input[2] = 11094488463398718754251685950409355128550342438297986977413505294941943071569;
+ input[3] = 6627643779954497813586310325594578844876646808666478625705401786271515864467;
+ input[4] = 2957286918163151606545409668133310005545945782087581890025685458369200827463;
+ input[5] = 1384290496819542862903939282897996566903332587607290986044945365745128311081;
+ input[6] = 5613571677741714971687805233468747950848449704454346829971683826953541367271;
+ input[7] = 9643208548031422463313148630985736896287522941726746581856185889848792022807;
+ input[8] = 18066496933330839731877828156604;
+ if (verify(input, proof) == 0) {
+ Verified("Transaction successfully verified.");
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ }
+ )";
+ compileAndRun(sourceCode, 0, "Pairing");
+ compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Pairing", m_contractAddress}});
+ // Disabled because the point seems to be not well-formed, we need to find another example.
+ //BOOST_CHECK(callContractFunction("testMul()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("pair()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("verifyTx()") == encodeArgs(true));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}