Skip to content
This repository was archived by the owner on Oct 28, 2021. It is now read-only.

Commit df9386b

Browse files
chrisethpirapira
authored andcommitted
Add snark primitives and pairing support
1 parent a58dae6 commit df9386b

File tree

10 files changed

+749
-43
lines changed

10 files changed

+749
-43
lines changed

CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ include(ProjectCryptopp)
6060
include(ProjectJsonCpp)
6161
include(ProjectJsonRpcCpp)
6262
include(ProjectSecp256k1)
63-
64-
63+
include(deps/snark.cmake)
6564

6665
configure_project()
6766

eth/main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#include <libethashseal/GenesisInfo.h>
4444
#include <libwebthree/WebThree.h>
4545

46+
#include <libdevcrypto/LibSnark.h>
47+
4648
#include <libweb3jsonrpc/AccountHolder.h>
4749
#include <libweb3jsonrpc/Eth.h>
4850
#include <libweb3jsonrpc/SafeHttpServer.h>

libdevcrypto/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ add_library(devcrypto ${SOURCES} ${HEADERS})
66
find_package(Utils)
77
target_include_directories(devcrypto PRIVATE ..)
88
target_include_directories(devcrypto PRIVATE ../utils)
9-
target_link_libraries(devcrypto Secp256k1 Cryptopp ${Utils_SCRYPT_LIBRARIES} devcore)
9+
target_link_libraries(devcrypto Secp256k1 Cryptopp snark ${Utils_SCRYPT_LIBRARIES} devcore)

libdevcrypto/Exceptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ namespace crypto
3030

3131
/// Rare malfunction of cryptographic functions.
3232
DEV_SIMPLE_EXCEPTION(CryptoException);
33+
DEV_SIMPLE_EXCEPTION(InvalidEncoding);
3334

3435
}
3536
}

libdevcrypto/LibSnark.cpp

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
This file is part of cpp-ethereum.
3+
4+
cpp-ethereum is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
cpp-ethereum is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
/**
18+
* @file LibSnark.cpp
19+
*/
20+
21+
#include <libdevcrypto/LibSnark.h>
22+
// libsnark has to be compiled with exactly the same switches:
23+
// sudo PREFIX=/usr/local make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 CURVE=ALT_BN128 FEATUREFLAGS="-DBINARY_OUTPUT=1 -DMONTGOMERY_OUTPUT=1 -DNO_PT_COMPRESSION=1" lib install
24+
#define BINARY_OUTPUT 1
25+
#define MONTGOMERY_OUTPUT 1
26+
#define NO_PT_COMPRESSION 1
27+
28+
#include <libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp>
29+
#include <libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp>
30+
#include <libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp>
31+
#include <libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp>
32+
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
33+
34+
#include <libdevcrypto/Exceptions.h>
35+
36+
#include <libdevcore/CommonIO.h>
37+
#include <libdevcore/Log.h>
38+
#include <libdevcore/FixedHash.h>
39+
40+
#include <fstream>
41+
42+
using namespace std;
43+
using namespace dev;
44+
using namespace dev::crypto;
45+
46+
namespace
47+
{
48+
49+
void initLibSnark()
50+
{
51+
static bool initialized = 0;
52+
if (!initialized)
53+
{
54+
libsnark::alt_bn128_pp::init_public_params();
55+
// Otherwise the library would output profiling info for each run.
56+
libsnark::inhibit_profiling_counters = true;
57+
libsnark::inhibit_profiling_info = true;
58+
initialized = true;
59+
}
60+
}
61+
62+
libsnark::bigint<libsnark::alt_bn128_q_limbs> toLibsnarkBigint(h256 const& _x)
63+
{
64+
libsnark::bigint<libsnark::alt_bn128_q_limbs> x;
65+
for (unsigned i = 0; i < 4; i++)
66+
for (unsigned j = 0; j < 8; j++)
67+
x.data[3 - i] |= uint64_t(_x[i * 8 + j]) << (8 * (7 - j));
68+
return x;
69+
}
70+
71+
h256 fromLibsnarkBigint(libsnark::bigint<libsnark::alt_bn128_q_limbs> _x)
72+
{
73+
h256 x;
74+
for (unsigned i = 0; i < 4; i++)
75+
for (unsigned j = 0; j < 8; j++)
76+
x[i * 8 + j] = uint8_t(uint64_t(_x.data[3 - i]) >> (8 * (7 - j)));
77+
return x;
78+
}
79+
80+
libsnark::alt_bn128_Fq decodeFqElement(dev::bytesConstRef _data)
81+
{
82+
// h256::AlignLeft ensures that the h256 is zero-filled on the right if _data
83+
// is too short.
84+
h256 xbin(_data, h256::AlignLeft);
85+
if (u256(xbin) >= u256(fromLibsnarkBigint(libsnark::alt_bn128_Fq::mod)))
86+
BOOST_THROW_EXCEPTION(InvalidEncoding());
87+
return toLibsnarkBigint(xbin);
88+
}
89+
90+
libsnark::alt_bn128_G1 decodePointG1(dev::bytesConstRef _data)
91+
{
92+
libsnark::alt_bn128_Fq X = decodeFqElement(_data.cropped(0));
93+
libsnark::alt_bn128_Fq Y = decodeFqElement(_data.cropped(32));
94+
if (X == libsnark::alt_bn128_Fq::zero() && Y == libsnark::alt_bn128_Fq::zero())
95+
return libsnark::alt_bn128_G1::zero();
96+
libsnark::alt_bn128_G1 p(X, Y, libsnark::alt_bn128_Fq::one());
97+
if (!p.is_well_formed())
98+
BOOST_THROW_EXCEPTION(InvalidEncoding());
99+
return p;
100+
}
101+
102+
bytes encodePointG1(libsnark::alt_bn128_G1 _p)
103+
{
104+
if (_p.is_zero())
105+
return h256().asBytes() + h256().asBytes();
106+
_p.to_affine_coordinates();
107+
return
108+
fromLibsnarkBigint(_p.X.as_bigint()).asBytes() +
109+
fromLibsnarkBigint(_p.Y.as_bigint()).asBytes();
110+
}
111+
112+
libsnark::alt_bn128_Fq2 decodeFq2Element(dev::bytesConstRef _data)
113+
{
114+
// Encoding: c1 (256 bits) c0 (256 bits)
115+
// "Big endian", just like the numbers
116+
return libsnark::alt_bn128_Fq2(
117+
decodeFqElement(_data.cropped(32)),
118+
decodeFqElement(_data.cropped(0))
119+
);
120+
}
121+
122+
123+
libsnark::alt_bn128_G2 decodePointG2(dev::bytesConstRef _data)
124+
{
125+
libsnark::alt_bn128_Fq2 X = decodeFq2Element(_data);
126+
libsnark::alt_bn128_Fq2 Y = decodeFq2Element(_data.cropped(64));
127+
if (X == libsnark::alt_bn128_Fq2::zero() && Y == libsnark::alt_bn128_Fq2::zero())
128+
return libsnark::alt_bn128_G2::zero();
129+
libsnark::alt_bn128_G2 p(X, Y, libsnark::alt_bn128_Fq2::one());
130+
if (!p.is_well_formed())
131+
BOOST_THROW_EXCEPTION(InvalidEncoding());
132+
return p;
133+
}
134+
135+
}
136+
137+
pair<bool, bytes> dev::crypto::alt_bn128_pairing_product(dev::bytesConstRef _in)
138+
{
139+
// Input: list of pairs of G1 and G2 points
140+
// Output: 1 if pairing evaluates to 1, 0 otherwise (left-padded to 32 bytes)
141+
142+
bool result = true;
143+
size_t const pairSize = 2 * 32 + 2 * 64;
144+
size_t const pairs = _in.size() / pairSize;
145+
if (pairs * pairSize != _in.size())
146+
{
147+
// Invalid length.
148+
return make_pair(false, bytes());
149+
}
150+
try
151+
{
152+
initLibSnark();
153+
libsnark::alt_bn128_Fq12 x = libsnark::alt_bn128_Fq12::one();
154+
for (size_t i = 0; i < pairs; ++i)
155+
{
156+
dev::bytesConstRef pair = _in.cropped(i * pairSize, pairSize);
157+
libsnark::alt_bn128_G2 p = decodePointG2(pair.cropped(2 * 32));
158+
if (-libsnark::alt_bn128_G2::scalar_field::one() * p + p != libsnark::alt_bn128_G2::zero())
159+
// p is not an element of the group (has wrong order)
160+
return {false, bytes()};
161+
x = x * libsnark::alt_bn128_miller_loop(
162+
libsnark::alt_bn128_precompute_G1(decodePointG1(pair)),
163+
libsnark::alt_bn128_precompute_G2(p)
164+
);
165+
}
166+
result = libsnark::alt_bn128_final_exponentiation(x) == libsnark::alt_bn128_GT::one();
167+
}
168+
catch (InvalidEncoding const&)
169+
{
170+
return make_pair(false, bytes());
171+
}
172+
catch (...)
173+
{
174+
cwarn << "Internal exception from libsnark. Forwarding as precompiled contract failure.";
175+
return make_pair(false, bytes());
176+
}
177+
178+
bytes res(32, 0);
179+
res[31] = unsigned(result);
180+
return {true, res};
181+
}
182+
183+
pair<bool, bytes> dev::crypto::alt_bn128_G1_add(dev::bytesConstRef _in)
184+
{
185+
try
186+
{
187+
initLibSnark();
188+
libsnark::alt_bn128_G1 p1 = decodePointG1(_in);
189+
libsnark::alt_bn128_G1 p2 = decodePointG1(_in.cropped(32 * 2));
190+
191+
return {true, encodePointG1(p1 + p2)};
192+
}
193+
catch (InvalidEncoding const&)
194+
{
195+
}
196+
catch (...)
197+
{
198+
cwarn << "Internal exception from libsnark. Forwarding as precompiled contract failure.";
199+
}
200+
return make_pair(false, bytes());
201+
}
202+
203+
pair<bool, bytes> dev::crypto::alt_bn128_G1_mul(dev::bytesConstRef _in)
204+
{
205+
try
206+
{
207+
initLibSnark();
208+
libsnark::alt_bn128_G1 p = decodePointG1(_in.cropped(0));
209+
210+
libsnark::alt_bn128_G1 result = toLibsnarkBigint(h256(_in.cropped(64), h256::AlignLeft)) * p;
211+
212+
return {true, encodePointG1(result)};
213+
}
214+
catch (InvalidEncoding const&)
215+
{
216+
}
217+
catch (...)
218+
{
219+
cwarn << "Internal exception from libsnark. Forwarding as precompiled contract failure.";
220+
}
221+
return make_pair(false, bytes());
222+
}

libdevcrypto/LibSnark.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
This file is part of cpp-ethereum.
3+
4+
cpp-ethereum is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
cpp-ethereum is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
/**
18+
* @file LibSnark.h
19+
*/
20+
21+
#pragma once
22+
23+
#include <libdevcore/Common.h>
24+
25+
namespace dev
26+
{
27+
namespace crypto
28+
{
29+
30+
std::pair<bool, bytes> alt_bn128_pairing_product(bytesConstRef _in);
31+
std::pair<bool, bytes> alt_bn128_G1_add(bytesConstRef _in);
32+
std::pair<bool, bytes> alt_bn128_G1_mul(bytesConstRef _in);
33+
34+
void exportVK(std::string const& _VKFilename);
35+
36+
}
37+
}

libethashseal/genesis/mainNetwork.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ R"E(
5555
"0000000000000000000000000000000000000002": { "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
5656
"0000000000000000000000000000000000000003": { "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
5757
"0000000000000000000000000000000000000004": { "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
58+
"0000000000000000000000000000000000000006": { "precompiled": { "name": "alt_bn128_G1_add", "startingBlock": "0xffffffffffffffffff", "linear": { "base": 15, "word": 3 } } },
59+
"0000000000000000000000000000000000000007": { "precompiled": { "name": "alt_bn128_G1_mul", "startingBlock": "0xffffffffffffffffff", "linear": { "base": 15, "word": 3 } } },
60+
"0000000000000000000000000000000000000008": { "precompiled": { "name": "alt_bn128_pairing_product", "startingBlock": "0xffffffffffffffffff", "linear": { "base": 15, "word": 3 } } },
5861
"3282791d6fd713f1e94f4bfd565eaa78b3a0599d": {
5962
"balance": "1337000000000000000000"
6063
},

libethashseal/genesis/metropolisTest.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ R"E(
5656
"0000000000000000000000000000000000000002": { "wei": "1", "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
5757
"0000000000000000000000000000000000000003": { "wei": "1", "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
5858
"0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
59-
"0000000000000000000000000000000000000005": { "wei": "1", "precompiled": { "name": "modexp" } }
60-
}
59+
"0000000000000000000000000000000000000006": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_add", "linear": { "base": 15, "word": 3 } } },
60+
"0000000000000000000000000000000000000007": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_mul", "linear": { "base": 15, "word": 3 } } },
61+
"0000000000000000000000000000000000000008": { "wei": "1", "precompiled": { "name": "alt_bn128_pairing_product", "linear": { "base": 15, "word": 3 } } },
62+
}
6163
}
6264
)E";

libethcore/Precompiled.cpp

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <libdevcore/SHA3.h>
2525
#include <libdevcrypto/Hash.h>
2626
#include <libdevcrypto/Common.h>
27+
#include <libdevcrypto/LibSnark.h>
2728
#include <libethcore/Common.h>
2829
using namespace std;
2930
using namespace dev;
@@ -97,50 +98,19 @@ ETH_REGISTER_PRECOMPILED(identity)(bytesConstRef _in)
9798
return {true, _in.toBytes()};
9899
}
99100

100-
// Parse _count bytes of _in starting with _begin offset as big endian int.
101-
// If there's not enough bytes in _in, consider it infinitely right-padded with zeroes.
102-
bigint parseBigEndianRightPadded(bytesConstRef _in, size_t _begin, size_t _count)
101+
ETH_REGISTER_PRECOMPILED(alt_bn128_pairing_product)(bytesConstRef _in)
103102
{
104-
if (_begin > _in.count())
105-
return 0;
106-
107-
// crop _in, not going beyond its size
108-
bytesConstRef cropped = _in.cropped(_begin, min(_count, _in.count() - _begin));
109-
110-
bigint ret = fromBigEndian<bigint>(cropped);
111-
// shift as if we had right-padding zeroes
112-
ret <<= 8 * (_count - cropped.count());
113-
114-
return ret;
103+
return dev::crypto::alt_bn128_pairing_product(_in);
115104
}
116105

117-
ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in)
106+
ETH_REGISTER_PRECOMPILED(alt_bn128_G1_add)(bytesConstRef _in)
118107
{
119-
size_t const baseLength(parseBigEndianRightPadded(_in, 0, 32));
120-
size_t const expLength(parseBigEndianRightPadded(_in, 32, 32));
121-
size_t const modLength(parseBigEndianRightPadded(_in, 64, 32));
122-
123-
bigint const base(parseBigEndianRightPadded(_in, 96, baseLength));
124-
bigint const exp(parseBigEndianRightPadded(_in, 96 + baseLength, expLength));
125-
bigint const mod(parseBigEndianRightPadded(_in, 96 + baseLength + expLength, modLength));
126-
127-
bigint const result = mod != 0 ? boost::multiprecision::powm(base, exp, mod) : bigint{0};
128-
129-
bytes ret(modLength);
130-
toBigEndian(result, ret);
131-
132-
return {true, ret};
108+
return dev::crypto::alt_bn128_G1_add(_in);
133109
}
134-
135-
ETH_REGISTER_PRECOMPILED_PRICER(modexp)(bytesConstRef _in)
110+
ETH_REGISTER_PRECOMPILED(alt_bn128_G1_mul)(bytesConstRef _in)
136111
{
137-
bigint const baseLength(parseBigEndianRightPadded(_in, 0, 32));
138-
bigint const expLength(parseBigEndianRightPadded(_in, 32, 32));
139-
bigint const modLength(parseBigEndianRightPadded(_in, 64, 32));
140-
141-
bigint const maxLength = max(modLength, baseLength);
142-
143-
return maxLength * maxLength * max<bigint>(expLength, 1) / 20;
112+
return dev::crypto::alt_bn128_G1_mul(_in);
144113
}
145114

115+
146116
}

0 commit comments

Comments
 (0)