-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Integrate libsnark #3587
Integrate libsnark #3587
Conversation
1746645
to
70b6758
Compare
@chfast please take over from here :-) |
please rebase |
Codecov Report
@@ Coverage Diff @@
## develop #3587 +/- ##
===========================================
+ Coverage 65.89% 66.28% +0.38%
===========================================
Files 303 305 +2
Lines 23046 23299 +253
===========================================
+ Hits 15186 15443 +257
+ Misses 7860 7856 -4
|
please rebase on develop so to point this PR to a test branch |
f175811
to
356b9c0
Compare
Progress: it builds on Windows, but tests fail. |
77369b3
to
e221f3e
Compare
@@ -57,7 +57,10 @@ R"E( | |||
"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 } } }, | |||
"0000000000000000000000000000000000000005": { "wei": "1", "precompiled": { "name": "modexp" } } | |||
"0000000000000000000000000000000000000005": { "wei": "1", "precompiled": { "name": "modexp" } } }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line has one too many }
. Really.
There is an input that crashes |
I prepared some tests for snark integration https://github.com/ethereum/tests/pull/171/files |
libdevcrypto/LibSnark.cpp
Outdated
{ | ||
// This is hackish, but we really want to use `static` variable for lock | ||
// free thread-safe initialization. | ||
static bool initialized = (libff::alt_bn128_pp::init_public_params(), true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So is init_public_params()
supposed to be called just once?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should first say if (!initialized)
in the beginning. Maybe we need to compare-and-swap initialized
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good idea.
You can use std::call_ones as a start.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's something new to me. Let me try this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, you can wrap the function to add some logs to make sure it is called, and it is called once.
libdevcrypto/LibSnark.cpp
Outdated
|
||
libff::alt_bn128_G1 decodePointG1(dev::bytesConstRef _data) | ||
{ | ||
libff::alt_bn128_Fq X = decodeFqElement(_data.cropped(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to specify the length as cropped(0, 32)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, now I see that the code is supposed to work even when _data
is shorter than 64 bytes.
libdevcrypto/LibSnark.cpp
Outdated
// is too short. | ||
h256 xbin(_data, h256::AlignLeft); | ||
if (u256(xbin) >= u256(fromLibsnarkBigint(libff::alt_bn128_Fq::mod))) | ||
BOOST_THROW_EXCEPTION(InvalidEncoding()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a more informative message here (especially the value of the modulo
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
libdevcrypto/LibSnark.cpp
Outdated
constexpr auto L = sizeof(x.data[0]); | ||
for (unsigned i = 0; i < N; i++) | ||
for (unsigned j = 0; j < L; j++) | ||
x.data[N - 1 - i] |= uint64_t(_x[i * L + j]) << (8 * (L - 1 - j)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a problem when x.data[0]
is wider than 64bit, but I'm not sure if we should go for
x.data[N - 1 - i] |= (std::remove_reference<decltype(x.data[0])>::type)(_x[i * L + j]) << (8 * (L - 1 - j));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I should just say libff::mp_limb_t
.
libff::alt_bn128_pp::init_public_params(); | ||
return true; | ||
}(); | ||
(void)s_initialized; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering why we need this boolean that we never read. Maybe doing this is enough?
[]() noexcept
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
libff::alt_bn128_pp::init_public_params();
}();
Or, do we even need the closure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need any static
variable to use thread-safe static initialization (aka magic statics). We can use call_once
here explicitly, but static vars are handled better by compilers.
What do you think? Go back to call_once
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to go back; I just wondered.
In the EIP PR, I asked for some clarification about the input length. ethereum/EIPs#212 (comment) I checked some other clients, and all of them required |
ebd5a90
to
dca57cd
Compare
libdevcrypto/LibSnark.cpp
Outdated
constexpr size_t L = sizeof(_b.data[0]); | ||
static_assert(sizeof(mp_limb_t) == L, "Unexpected limb size in libff::bigint."); | ||
h256 x; | ||
for (size_t i = 0; i < N; i++) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get the following error. Maybe it helps to specify the type of N
.
libdevcrypto/LibSnark.cpp:68:23: error: comparison of integers of different signs: 'size_t' (aka 'unsigned long') and 'const long' [-Werror,-Wsign-compare]
for (size_t i = 0; i < N; i++)
libdevcrypto/LibSnark.cpp
Outdated
libff::alt_bn128_G2 decodePointG2(dev::bytesConstRef _data) | ||
{ | ||
libff::alt_bn128_Fq2 x = decodeFq2Element(_data); | ||
libff::alt_bn128_Fq2 y = decodeFq2Element(_data.cropped(64)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
x
and y
can be const
.
libdevcrypto/LibSnark.cpp
Outdated
if (x == libff::alt_bn128_Fq2::zero() && y == libff::alt_bn128_Fq2::zero()) | ||
return libff::alt_bn128_G2::zero(); | ||
libff::alt_bn128_G2 p(x, y, libff::alt_bn128_Fq2::one()); | ||
if (!p.is_well_formed()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p
can also be const
.
libdevcrypto/LibSnark.cpp
Outdated
{ | ||
// Invalid length. | ||
return {false, bytes{}}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: we don't have braces around a single-line body of if
.
libdevcrypto/LibSnark.cpp
Outdated
for (size_t i = 0; i < pairs; ++i) | ||
{ | ||
dev::bytesConstRef pair = _in.cropped(i * pairSize, pairSize); | ||
libff::alt_bn128_G2 p = decodePointG2(pair.cropped(2 * 32)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pair
and p
can be const
.
libdevcrypto/LibSnark.cpp
Outdated
} | ||
catch (...) | ||
{ | ||
cwarn << "Internal exception from libsnark. Forwarding as precompiled contract failure."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps, we should look into the library, and see which exception is supposed to happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not throw any exceptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we silence unexpected exceptions here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer not to. It's better to terminate the node in this case than running it in invalid state mode. Agree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree.
Ok, I will handle these. |
d824b64
to
5b383c5
Compare
Handle only expected exceptions around snark primitives precompiled, pass anything else higher.
Great! Waiting for CI tests... |
All green. |
Implements ethereum/EIPs#212 and ethereum/EIPs#213
Fixes #3619 (comment)
This is still work in progress.
src/algebra/curves/alt_bn128/
- this requires patching the makefile.