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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ cache:
# build external dependencies next build.
- $TRAVIS_BUILD_DIR/deps
install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then clang --version; brew install llvm; $(brew --prefix llvm)/bin/clang --version; export PATH=$(brew --prefix llvm)/bin:$PATH; export CC=$(brew --prefix llvm)/bin/clang; export CXX=$(brew --prefix llvm)/bin/clang++; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./scripts/install_cmake.sh; fi
- ./scripts/install_deps.sh
before_script:
Expand Down
3 changes: 1 addition & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ include(ProjectCryptopp)
include(ProjectJsonCpp)
include(ProjectJsonRpcCpp)
include(ProjectSecp256k1)


include(ProjectSnark)

configure_project()

Expand Down
19 changes: 10 additions & 9 deletions cmake/ProjectBoost.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -36,45 +36,46 @@ ExternalProject_Add(boost
--with-regex
--with-test
--with-thread
--with-program_options # libff wants it, we may need it in future.
LOG_BUILD 1
INSTALL_COMMAND ""
)

ExternalProject_Get_Property(boost SOURCE_DIR)
set(BOOST_INCLUDE_DIR ${SOURCE_DIR})
set(BOOST_LIB_DIR ${SOURCE_DIR}/stage/lib)
set(BOOST_LIBRARY_DIR ${SOURCE_DIR}/stage/lib)
unset(BUILD_DIR)

add_library(Boost::Chrono STATIC IMPORTED)
set_property(TARGET Boost::Chrono PROPERTY IMPORTED_LOCATION ${BOOST_LIB_DIR}/libboost_chrono${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::Chrono PROPERTY IMPORTED_LOCATION ${BOOST_LIBRARY_DIR}/libboost_chrono${BOOST_LIBRARY_SUFFIX})
add_dependencies(Boost::Chrono boost)

add_library(Boost::DataTime STATIC IMPORTED)
set_property(TARGET Boost::DataTime PROPERTY IMPORTED_LOCATION ${BOOST_LIB_DIR}/libboost_date_time${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::DataTime PROPERTY IMPORTED_LOCATION ${BOOST_LIBRARY_DIR}/libboost_date_time${BOOST_LIBRARY_SUFFIX})
add_dependencies(Boost::DataTime boost)

add_library(Boost::Regex STATIC IMPORTED)
set_property(TARGET Boost::Regex PROPERTY IMPORTED_LOCATION ${BOOST_LIB_DIR}/libboost_regex${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::Regex PROPERTY IMPORTED_LOCATION ${BOOST_LIBRARY_DIR}/libboost_regex${BOOST_LIBRARY_SUFFIX})
add_dependencies(Boost::Regex boost)

add_library(Boost::System STATIC IMPORTED)
set_property(TARGET Boost::System PROPERTY IMPORTED_LOCATION ${BOOST_LIB_DIR}/libboost_system${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::System PROPERTY IMPORTED_LOCATION ${BOOST_LIBRARY_DIR}/libboost_system${BOOST_LIBRARY_SUFFIX})
add_dependencies(Boost::System boost)

add_library(Boost::Filesystem STATIC IMPORTED)
set_property(TARGET Boost::Filesystem PROPERTY IMPORTED_LOCATION ${BOOST_LIB_DIR}/libboost_filesystem${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::Filesystem PROPERTY IMPORTED_LOCATION ${BOOST_LIBRARY_DIR}/libboost_filesystem${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::Filesystem PROPERTY INTERFACE_LINK_LIBRARIES Boost::System)
add_dependencies(Boost::Filesystem boost)

add_library(Boost::Random STATIC IMPORTED)
set_property(TARGET Boost::Random PROPERTY IMPORTED_LOCATION ${BOOST_LIB_DIR}/libboost_random${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::Random PROPERTY IMPORTED_LOCATION ${BOOST_LIBRARY_DIR}/libboost_random${BOOST_LIBRARY_SUFFIX})
add_dependencies(Boost::Random boost)

add_library(Boost::UnitTestFramework STATIC IMPORTED)
set_property(TARGET Boost::UnitTestFramework PROPERTY IMPORTED_LOCATION ${BOOST_LIB_DIR}/libboost_unit_test_framework${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::UnitTestFramework PROPERTY IMPORTED_LOCATION ${BOOST_LIBRARY_DIR}/libboost_unit_test_framework${BOOST_LIBRARY_SUFFIX})
add_dependencies(Boost::UnitTestFramework boost)

add_library(Boost::Thread STATIC IMPORTED)
set_property(TARGET Boost::Thread PROPERTY IMPORTED_LOCATION ${BOOST_LIB_DIR}/libboost_thread${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::Thread PROPERTY IMPORTED_LOCATION ${BOOST_LIBRARY_DIR}/libboost_thread${BOOST_LIBRARY_SUFFIX})
set_property(TARGET Boost::Thread PROPERTY INTERFACE_LINK_LIBRARIES Boost::Chrono Boost::DataTime Boost::Regex)
add_dependencies(Boost::Thread boost)
19 changes: 19 additions & 0 deletions cmake/ProjectMPIR.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
ExternalProject_Add(mpir
PREFIX ${CMAKE_SOURCE_DIR}/deps
DOWNLOAD_NAME mpir-cmake.tar.gz
DOWNLOAD_NO_PROGRESS TRUE
URL https://github.com/chfast/mpir/archive/cmake.tar.gz
URL_HASH SHA256=2bf35ad7aa2b61bf4c2dcdab9aab48b2b4f9d6db8b937be4b0b5fe3b5efbdfa6
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DCMAKE_BUILD_TYPE=Debug
-DMPIR_GMP=On
)

ExternalProject_Get_Property(mpir INSTALL_DIR)
add_library(MPIR::mpir STATIC IMPORTED)
set(MPIR_LIBRARY ${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}mpir${CMAKE_STATIC_LIBRARY_SUFFIX})
set(MPIR_INCLUDE_DIR ${INSTALL_DIR}/include)
set_property(TARGET MPIR::mpir PROPERTY IMPORTED_LOCATION ${MPIR_LIBRARY})
set_property(TARGET MPIR::mpir PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MPIR_INCLUDE_DIR})
add_dependencies(MPIR::mpir mpir)
unset(INSTALL_DIR)
33 changes: 33 additions & 0 deletions cmake/ProjectSnark.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
include(ProjectMPIR)

# FIXME: Rename to LibFF as that's the name of the library.

ExternalProject_Add(snark
PREFIX ${CMAKE_SOURCE_DIR}/deps
DOWNLOAD_NAME libff-97d3fa6c.tar.gz
DOWNLOAD_NO_PROGRESS TRUE
URL https://github.com/chfast/libff/archive/97d3fa6cdbd4b7549c7a8a179dc97308dbfd044d.tar.gz
URL_HASH SHA256=f102f3ee43c96c9a81c20d8c0446c805c6b8c0e3121518b3625f08e2c230096e
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DGMP_INCLUDE_DIR=${MPIR_INCLUDE_DIR}
-DGMP_LIBRARIES=${MPIR_LIBRARY}
-DGMPXX_LIBRARIES=${MPIR_LIBRARY}
-DCURVE=ALT_BN128 -DPERFORMANCE=Off -DWITH_PROCPS=Off
-DUSE_PT_COMPRESSION=Off
BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config Release
INSTALL_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config Release --target install
)
add_dependencies(snark boost)
add_dependencies(snark mpir)

# Create snark imported library
ExternalProject_Get_Property(snark INSTALL_DIR)
add_library(Snark STATIC IMPORTED)
set(SNARK_LIBRARY ${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}ff${CMAKE_STATIC_LIBRARY_SUFFIX})
set(SNARK_INCLUDE_DIR ${INSTALL_DIR}/include/libff)
file(MAKE_DIRECTORY ${SNARK_INCLUDE_DIR})
set_property(TARGET Snark PROPERTY IMPORTED_LOCATION ${SNARK_LIBRARY})
set_property(TARGET Snark PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${SNARK_INCLUDE_DIR})
set_property(TARGET Snark PROPERTY INTERFACE_LINK_LIBRARIES MPIR::mpir)
add_dependencies(Snark snark)
unset(INSTALL_DIR)
2 changes: 2 additions & 0 deletions eth/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#include <libethashseal/GenesisInfo.h>
#include <libwebthree/WebThree.h>

#include <libdevcrypto/LibSnark.h>

#include <libweb3jsonrpc/AccountHolder.h>
#include <libweb3jsonrpc/Eth.h>
#include <libweb3jsonrpc/SafeHttpServer.h>
Expand Down
2 changes: 1 addition & 1 deletion libdevcrypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ add_library(devcrypto ${SOURCES} ${HEADERS})
find_package(Utils)
target_include_directories(devcrypto PRIVATE ..)
target_include_directories(devcrypto PRIVATE ../utils)
target_link_libraries(devcrypto Secp256k1 Cryptopp ${Utils_SCRYPT_LIBRARIES} devcore)
target_link_libraries(devcrypto Secp256k1 Snark Cryptopp ${Utils_SCRYPT_LIBRARIES} devcore)
202 changes: 202 additions & 0 deletions libdevcrypto/LibSnark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
This file is part of cpp-ethereum.

cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/

#include <libdevcrypto/LibSnark.h>

#include <algebra/curves/alt_bn128/alt_bn128_g1.hpp>
#include <algebra/curves/alt_bn128/alt_bn128_g2.hpp>
#include <algebra/curves/alt_bn128/alt_bn128_pairing.hpp>
#include <algebra/curves/alt_bn128/alt_bn128_pp.hpp>
#include <common/profiling.hpp>

#include <libdevcore/Exceptions.h>
#include <libdevcore/Log.h>

using namespace std;
using namespace dev;
using namespace dev::crypto;

namespace
{

DEV_SIMPLE_EXCEPTION(InvalidEncoding);

void initLibSnark() noexcept
{
static bool s_initialized = []() noexcept
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
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.

}

libff::bigint<libff::alt_bn128_q_limbs> toLibsnarkBigint(h256 const& _x)
{
libff::bigint<libff::alt_bn128_q_limbs> b;
auto const N = b.N;
constexpr size_t L = sizeof(b.data[0]);
static_assert(sizeof(mp_limb_t) == L, "Unexpected limb size in libff::bigint.");
for (size_t i = 0; i < N; i++)
for (size_t j = 0; j < L; j++)
b.data[N - 1 - i] |= mp_limb_t(_x[i * L + j]) << (8 * (L - 1 - j));
return b;
}

h256 fromLibsnarkBigint(libff::bigint<libff::alt_bn128_q_limbs> const& _b)
{
static size_t const N = static_cast<size_t>(_b.N);
static size_t const 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++)
for (size_t j = 0; j < L; j++)
x[i * L + j] = uint8_t(_b.data[N - 1 - i] >> (8 * (L - 1 - j)));
return x;
}

libff::alt_bn128_Fq decodeFqElement(dev::bytesConstRef _data)
{
// h256::AlignLeft ensures that the h256 is zero-filled on the right if _data
// is too short.
h256 xbin(_data, h256::AlignLeft);
// TODO: Consider using a compiler time constant for comparison.
if (u256(xbin) >= u256(fromLibsnarkBigint(libff::alt_bn128_Fq::mod)))
BOOST_THROW_EXCEPTION(InvalidEncoding());
return toLibsnarkBigint(xbin);
}

libff::alt_bn128_G1 decodePointG1(dev::bytesConstRef _data)
{
libff::alt_bn128_Fq x = decodeFqElement(_data.cropped(0));
libff::alt_bn128_Fq y = decodeFqElement(_data.cropped(32));
if (x == libff::alt_bn128_Fq::zero() && y == libff::alt_bn128_Fq::zero())
return libff::alt_bn128_G1::zero();
libff::alt_bn128_G1 p(x, y, libff::alt_bn128_Fq::one());
if (!p.is_well_formed())
BOOST_THROW_EXCEPTION(InvalidEncoding());
return p;
}

bytes encodePointG1(libff::alt_bn128_G1 _p)
{
if (_p.is_zero())
return bytes(64, 0);
_p.to_affine_coordinates();
return
fromLibsnarkBigint(_p.X.as_bigint()).asBytes() +
fromLibsnarkBigint(_p.Y.as_bigint()).asBytes();
}

libff::alt_bn128_Fq2 decodeFq2Element(dev::bytesConstRef _data)
{
// Encoding: c1 (256 bits) c0 (256 bits)
// "Big endian", just like the numbers
return libff::alt_bn128_Fq2(
decodeFqElement(_data.cropped(32)),
decodeFqElement(_data.cropped(0))
);
}

libff::alt_bn128_G2 decodePointG2(dev::bytesConstRef _data)
{
libff::alt_bn128_Fq2 const x = decodeFq2Element(_data);
libff::alt_bn128_Fq2 const y = decodeFq2Element(_data.cropped(64));
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())
BOOST_THROW_EXCEPTION(InvalidEncoding());
return p;
}

}

pair<bool, bytes> dev::crypto::alt_bn128_pairing_product(dev::bytesConstRef _in)
{
// Input: list of pairs of G1 and G2 points
// Output: 1 if pairing evaluates to 1, 0 otherwise (left-padded to 32 bytes)

size_t constexpr pairSize = 2 * 32 + 2 * 64;
size_t const pairs = _in.size() / pairSize;
if (pairs * pairSize != _in.size())
// Invalid length.
return {false, bytes{}};

try
{
initLibSnark();
libff::alt_bn128_Fq12 x = libff::alt_bn128_Fq12::one();
for (size_t i = 0; i < pairs; ++i)
{
bytesConstRef const pair = _in.cropped(i * pairSize, pairSize);
libff::alt_bn128_G2 const p = decodePointG2(pair.cropped(2 * 32));
if (-libff::alt_bn128_G2::scalar_field::one() * p + p != libff::alt_bn128_G2::zero())
// p is not an element of the group (has wrong order)
return {false, bytes()};
if (p.is_zero())
continue; // the pairing is one
if (decodePointG1(pair).is_zero())
continue; // the pairing is one
x = x * libff::alt_bn128_miller_loop(
libff::alt_bn128_precompute_G1(decodePointG1(pair)),
libff::alt_bn128_precompute_G2(p)
);
}
bool const result = libff::alt_bn128_final_exponentiation(x) == libff::alt_bn128_GT::one();
return {true, h256{result}.asBytes()};
}
catch (InvalidEncoding const&)
{
// Signal the call failure for invalid input.
return {false, bytes{}};
}
}

pair<bool, bytes> dev::crypto::alt_bn128_G1_add(dev::bytesConstRef _in)
{
try
{
initLibSnark();
libff::alt_bn128_G1 const p1 = decodePointG1(_in);
libff::alt_bn128_G1 const p2 = decodePointG1(_in.cropped(32 * 2));
return {true, encodePointG1(p1 + p2)};
}
catch (InvalidEncoding const&)
{
// Signal the call failure for invalid input.
return {false, bytes{}};
}
}

pair<bool, bytes> dev::crypto::alt_bn128_G1_mul(dev::bytesConstRef _in)
{
try
{
initLibSnark();
libff::alt_bn128_G1 const p = decodePointG1(_in.cropped(0));
libff::alt_bn128_G1 const result = toLibsnarkBigint(h256(_in.cropped(64), h256::AlignLeft)) * p;
return {true, encodePointG1(result)};
}
catch (InvalidEncoding const&)
{
// Signal the call failure for invalid input.
return {false, bytes{}};
}
}
35 changes: 35 additions & 0 deletions libdevcrypto/LibSnark.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
This file is part of cpp-ethereum.

cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file LibSnark.h
*/

#pragma once

#include <libdevcore/Common.h>

namespace dev
{
namespace crypto
{

std::pair<bool, bytes> alt_bn128_pairing_product(bytesConstRef _in);
std::pair<bool, bytes> alt_bn128_G1_add(bytesConstRef _in);
std::pair<bool, bytes> alt_bn128_G1_mul(bytesConstRef _in);

}
}
3 changes: 3 additions & 0 deletions libethashseal/genesis/mainNetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ R"E(
"0000000000000000000000000000000000000002": { "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
"0000000000000000000000000000000000000003": { "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
"0000000000000000000000000000000000000004": { "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
"0000000000000000000000000000000000000006": { "precompiled": { "name": "alt_bn128_G1_add", "startingBlock": "0xffffffffffffffffff", "linear": { "base": 500, "word": 0 } } },
"0000000000000000000000000000000000000007": { "precompiled": { "name": "alt_bn128_G1_mul", "startingBlock": "0xffffffffffffffffff", "linear": { "base": 2000, "word": 0 } } },
"0000000000000000000000000000000000000008": { "precompiled": { "name": "alt_bn128_pairing_product", "startingBlock": "0xffffffffffffffffff" } },
"3282791d6fd713f1e94f4bfd565eaa78b3a0599d": {
"balance": "1337000000000000000000"
},
Expand Down
Loading