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

Integrate libsnark #3587

Merged
merged 10 commits into from
Jun 13, 2017
Merged

Integrate libsnark #3587

merged 10 commits into from
Jun 13, 2017

Conversation

chriseth
Copy link
Contributor

@chriseth chriseth commented Feb 22, 2017

Implements ethereum/EIPs#212 and ethereum/EIPs#213
Fixes #3619 (comment)

This is still work in progress.

  • change point encoding
  • remove unnecessary stuff
  • make this work for truncated input
  • we can probably patch libsnark to remove all cpp files outside the directory src/algebra/curves/alt_bn128/ - this requires patching the makefile.
  • add source hash for external dependency
  • move unittest file to the right place
  • clean up git history
  • check edge cases for pairing

@chriseth chriseth force-pushed the snark branch 4 times, most recently from 1746645 to 70b6758 Compare February 28, 2017 19:14
@chriseth
Copy link
Contributor Author

@chfast please take over from here :-)

@chfast chfast self-assigned this Mar 1, 2017
@winsvega
Copy link
Contributor

winsvega commented Mar 2, 2017

please rebase

@chfast chfast added this to the Metropolis milestone Mar 3, 2017
@codecov-io
Copy link

codecov-io commented Mar 7, 2017

Codecov Report

Merging #3587 into develop will increase coverage by 0.38%.
The diff coverage is 99.6%.

@@             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
Impacted Files Coverage Δ
libethashseal/genesis/mainNetwork.cpp 100% <ø> (ø) ⬆️
libethashseal/genesis/metropolisTest.cpp 100% <ø> (ø) ⬆️
test/tools/libtesteth/ImportTest.cpp 49.61% <100%> (ø) ⬆️
test/unittests/libdevcrypto/LibSnark.cpp 100% <100%> (ø)
test/tools/libtesteth/boostTest.cpp 55.1% <100%> (ø) ⬆️
test/tools/jsontests/StateTests.cpp 95.23% <100%> (+0.05%) ⬆️
libethcore/Precompiled.cpp 94.91% <100%> (+0.79%) ⬆️
libdevcrypto/LibSnark.cpp 98.85% <98.85%> (ø)
test/tools/fuzzTesting/fuzzHelper.cpp 31.86% <0%> (-1.97%) ⬇️
... and 5 more

@winsvega
Copy link
Contributor

winsvega commented Mar 30, 2017

please rebase on develop so to point this PR to a test branch
hm. cant refill zeroKnowledge tests. dedlock of some kind

@chfast chfast force-pushed the snark branch 2 times, most recently from f175811 to 356b9c0 Compare April 21, 2017 12:40
@chfast
Copy link
Member

chfast commented Apr 21, 2017

Progress: it builds on Windows, but tests fail.

@chfast chfast force-pushed the snark branch 3 times, most recently from 77369b3 to e221f3e Compare May 8, 2017 20:51
@@ -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" } } },
Copy link
Member

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.

@pirapira
Copy link
Member

There is an input that crashes libff (Pairing with the zero-element of G2). The fix is pirapira@958a69c

@pirapira
Copy link
Member

I prepared some tests for snark integration https://github.com/ethereum/tests/pull/171/files

@pirapira pirapira dismissed their stale review May 22, 2017 10:10

I pushed a fix for my comment.

{
// 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);
Copy link
Member

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?

Copy link
Member

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.

Copy link
Member

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.

Copy link
Member

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.

Copy link
Member

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.


libff::alt_bn128_G1 decodePointG1(dev::bytesConstRef _data)
{
libff::alt_bn128_Fq X = decodeFqElement(_data.cropped(0));
Copy link
Member

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).

Copy link
Member

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.

// is too short.
h256 xbin(_data, h256::AlignLeft);
if (u256(xbin) >= u256(fromLibsnarkBigint(libff::alt_bn128_Fq::mod)))
BOOST_THROW_EXCEPTION(InvalidEncoding());
Copy link
Member

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).

Copy link
Contributor Author

@chriseth chriseth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

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));
Copy link
Member

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));

Copy link
Member

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;
Copy link
Member

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?

Copy link
Member

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?

Copy link
Member

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.

@pirapira
Copy link
Member

pirapira commented Jun 9, 2017

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 input_length % 192 == 0 for the pairing checker.

@chfast chfast force-pushed the snark branch 2 times, most recently from ebd5a90 to dca57cd Compare June 9, 2017 11:54
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++)
Copy link
Member

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++)

libff::alt_bn128_G2 decodePointG2(dev::bytesConstRef _data)
{
libff::alt_bn128_Fq2 x = decodeFq2Element(_data);
libff::alt_bn128_Fq2 y = decodeFq2Element(_data.cropped(64));
Copy link
Member

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.

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())
Copy link
Member

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.

{
// Invalid length.
return {false, bytes{}};
}
Copy link
Member

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.

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));
Copy link
Member

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.

}
catch (...)
{
cwarn << "Internal exception from libsnark. Forwarding as precompiled contract failure.";
Copy link
Member

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.

Copy link
Member

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.

Copy link
Member

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?

Copy link
Member

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree.

@chfast
Copy link
Member

chfast commented Jun 12, 2017

Ok, I will handle these.

@chfast chfast force-pushed the snark branch 2 times, most recently from d824b64 to 5b383c5 Compare June 12, 2017 15:21
@chfast
Copy link
Member

chfast commented Jun 13, 2017

Great! Waiting for CI tests...

@pirapira
Copy link
Member

All green.

@pirapira pirapira merged commit 8f8edab into develop Jun 13, 2017
@pirapira pirapira deleted the snark branch June 13, 2017 17:40
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants