Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update bn256 to c++20 #17

Merged
merged 17 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from 15 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
6 changes: 6 additions & 0 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: true
- name: 'setup'
if: contains(matrix.config.vm_image, '20.04')
run: |
sudo apt-get install -y g++-10 libstdc++-10-dev
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 \
--slave /usr/bin/gcc gcc /usr/bin/gcc-10
- name: 'configure'
run: |
cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.mode }} -Bbuild -S.
Expand Down
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
[submodule "third-party/Catch2"]
path = third-party/Catch2
url = https://github.com/catchorg/Catch2
[submodule "third-party/span"]
path = third-party/span
url = https://github.com/martinmoene/span-lite
22 changes: 12 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
cmake_minimum_required(VERSION 3.8)
project(bn256 VERSION 1.0.0)
cmake_minimum_required(VERSION 3.12)

set(CMAKE_CXX_STANDARD 17)
# set version and extract major version (currently version_major is 1).
set(version 1.1.0)
string(REPLACE "." ";" version_list ${version}) # transform into list
list(GET version_list 0 version_major)

project(bn256 VERSION ${version})

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 you can do project(bn256 VERSION 1.1.0) here and then use bn256_VERSION_MAJOR elsewhere, instead of doing that parsing stuff.

But it seems to me like this ought to be a 2.0.0 version instead, since don't these changes break the ABI?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you can do project(bn256 VERSION 1.1.0) here and then use bn256_VERSION_MAJOR elsewhere,

yes, that works, thanks!

But it seems to me like this ought to be a 2.0.0 version instead

Hum, I'm not sure how to tell for sure, but I'm happy to switch to 2.0.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 mostly academic on 1.0.0 vs 1.1.0 vs 2.0.0 for many reasons.. but setting things like

bn256/CMakeLists.txt

Lines 23 to 25 in b20f7f5

set_property(TARGET bn256 PROPERTY SOVERSION ${bn256_VERSION_MAJOR})
set_property(TARGET bn256 PROPERTY INTERFACE_bn256_MAJOR_VERSION ${bn256_VERSION_MAJOR})
set_property(TARGET bn256 APPEND PROPERTY COMPATIBLE_INTERFACE_STRING bn256_MAJOR_VERSION)

shows an intent to version and since std::span is part of the public interface, switching from "not really std::span" to std::span breaks usage of the library if it had been built as a shared library and installed. Again.. that seems like a stretch of a use case.. but maybe.

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_EXTENSIONS ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_compile_options(-Wall)
Expand All @@ -18,14 +24,10 @@ if(BN256_ENABLE_TEST)
endif()

include(GNUInstallDirs)
set(version 1.0.0)
set_property(TARGET bn256 PROPERTY VERSION ${version})
set_property(TARGET bn256 PROPERTY SOVERSION 1)
set_property(TARGET bn256 PROPERTY
INTERFACE_bn256_MAJOR_VERSION 1)
set_property(TARGET bn256 APPEND PROPERTY
COMPATIBLE_INTERFACE_STRING bn256_MAJOR_VERSION
)
set_property(TARGET bn256 PROPERTY SOVERSION ${version_major})
set_property(TARGET bn256 PROPERTY INTERFACE_bn256_MAJOR_VERSION ${version_major})
set_property(TARGET bn256 APPEND PROPERTY COMPATIBLE_INTERFACE_STRING bn256_MAJOR_VERSION)

install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(DIRECTORY third-party/span/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bn256)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# BN256 Cryptographic Library
## Version : 1.0
## Version : 1.1
Copy link
Member

Choose a reason for hiding this comment

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

probably want 2.0 here too


This library implements the bilinear group `BN256` in the C++ language. It is based off of the [cloudflare/bn256](https://github.com/ethereum/go-ethereum/tree/master/crypto/bn256/cloudflare) implementation.

Expand Down
2 changes: 1 addition & 1 deletion include/bn256/bn256.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include <cstring>
#include <functional>
#include <cstdint>
#include <bn256/span.h>
#include <span>

namespace bn256 {

Expand Down
12 changes: 0 additions & 12 deletions include/bn256/span.h

This file was deleted.

81 changes: 20 additions & 61 deletions src/array.h
Original file line number Diff line number Diff line change
@@ -1,51 +1,10 @@
#pragma once
#include <cstddef>
#include <cstring>
#if __cplusplus > 201703L
#include <span>
#include <cstdint>
#include <tuple>
#include <array>
namespace bn256 {
template <typename T, std::size_t S>
using array = std::array<T, S>;
}
#else
#include <bn256/span.h>

namespace bn256 {
// std::array in C++17 cannot be used in constexpr context; therefore we rollout our own.
template <typename T, std::size_t N>
struct array {
T v_[N];
constexpr T& operator[](std::size_t i) noexcept { return v_[i]; }
constexpr const T& operator[](std::size_t i) const noexcept { return v_[i]; }
constexpr std::size_t size() const noexcept { return N; }
constexpr T* data() noexcept { return v_; }
constexpr const T* data() const noexcept { return v_; }

constexpr const T* begin() const noexcept { return v_; }
constexpr const T* end() const noexcept { return v_+N; }

constexpr bool operator==(const array<T, N>& other) const noexcept {
for (std::size_t i = 0; i < N; ++i)
if (v_[i] != other[i])
return false;
return true;
}

constexpr bool operator!=(const array& other) const noexcept { return !(*this == other); }

constexpr operator std::span<T,N> () noexcept {
return std::span<T,N> {v_};
}

constexpr operator std::span<const T,N> () const noexcept {
return std::span<const T,N> {v_};
}
};
} // namespace bn256
#endif
#include <span>
#include <cstdint>
#include <tuple>
#include <array>

namespace bn256 {
template <std::size_t N>
Expand All @@ -62,22 +21,22 @@ constexpr int bitlen(std::span<const uint64_t, N> a) {
return bit_length - __builtin_clzll(all_sign_bits == 0 ? a[i] : -a[i]);
}

static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0, 0x0FFFFFFFFFFFFFFF}) == 252);
static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0x0FFFFFFFFFFFFFFF, 0}) == 188);
static_assert(bitlen<4>(array<uint64_t,4>{0x0FFFFFFFFFFFFFFF, 0, 0, 0}) == 60);
static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0, 0x8FFFFFFFFFFFFFFF}) == 255);
static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0, 0x7FFFFFFFFFFFFFFF}) == 255);
static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}) == 192);
static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0x7FFFFFFFFFFFFFFF, 0}) == 191);
static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0x8FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}) == 191);
static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0x8FFFFFFFFFFFFFFF, 0}) == 192);
static_assert(bitlen<4>(array<uint64_t,4>{0x7FFFFFFFFFFFFFFF, 0, 0, 0}) == 63);
static_assert(bitlen<4>(array<uint64_t,4>{0x8FFFFFFFFFFFFFFF, 0, 0, 0}) == 64);
static_assert(bitlen<4>(array<uint64_t,4>{0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}) == 64);
static_assert(bitlen<4>(array<uint64_t,4>{0x8FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}) == 63);
static_assert(bitlen<4>(array<uint64_t,4>{0, 0, 0, 0}) == 0);

constexpr int bitlen(const array<uint64_t, 4>& a) {
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0, 0x0FFFFFFFFFFFFFFF}) == 252);
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0x0FFFFFFFFFFFFFFF, 0}) == 188);
static_assert(bitlen<4>(std::array<uint64_t,4>{0x0FFFFFFFFFFFFFFF, 0, 0, 0}) == 60);
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0, 0x8FFFFFFFFFFFFFFF}) == 255);
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0, 0x7FFFFFFFFFFFFFFF}) == 255);
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}) == 192);
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0x7FFFFFFFFFFFFFFF, 0}) == 191);
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0x8FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}) == 191);
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0x8FFFFFFFFFFFFFFF, 0}) == 192);
static_assert(bitlen<4>(std::array<uint64_t,4>{0x7FFFFFFFFFFFFFFF, 0, 0, 0}) == 63);
static_assert(bitlen<4>(std::array<uint64_t,4>{0x8FFFFFFFFFFFFFFF, 0, 0, 0}) == 64);
static_assert(bitlen<4>(std::array<uint64_t,4>{0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}) == 64);
static_assert(bitlen<4>(std::array<uint64_t,4>{0x8FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}) == 63);
static_assert(bitlen<4>(std::array<uint64_t,4>{0, 0, 0, 0}) == 0);

constexpr int bitlen(const std::array<uint64_t, 4>& a) {
return bitlen<4>(std::span<const uint64_t, 4>(a));
}

Expand Down
2 changes: 1 addition & 1 deletion src/curve.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ struct curve_point {
curve_point mul(std::span<const uint64_t, 4> scalar) const noexcept {
const curve_point& a = *this;

array<curve_point, 4> precomp{};
std::array<curve_point, 4> precomp{};

precomp[1] = a;
precomp[2] = a;
Expand Down
20 changes: 10 additions & 10 deletions src/gfp.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@
#include <iosfwd>
#include <string>
#include <system_error>
#include <bn256/span.h>
#include <span>

namespace bn256 {

enum class unmarshal_error { NO_ERROR = 0, COORDINATE_EXCEEDS_MODULUS = 1, COORDINATE_EQUALS_MODULUS, MALFORMED_POINT };

namespace constants {
// rn1 is R^-1 where R = 2^256 mod p.
inline constexpr array<uint64_t, 4> rn1 = { 0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9,
0x2e67157159e5c639 };
inline constexpr std::array<uint64_t, 4> rn1 = { 0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9,
0x2e67157159e5c639 };

// r2 is R^2 where R = 2^256 mod p.
inline constexpr array<uint64_t, 4> r2 = { 0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6,
0x06d89f71cab8351f };
inline constexpr std::array<uint64_t, 4> r2 = { 0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6,
0x06d89f71cab8351f };

// r3 is R^3 where R = 2^256 mod p.
inline constexpr array<uint64_t, 4> r3 = { 0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb,
0x20fd6e902d592544 };
inline constexpr std::array<uint64_t, 4> r3 = { 0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb,
0x20fd6e902d592544 };
} // namespace constants

struct gfp : array<uint64_t, 4> {
struct gfp : std::array<uint64_t, 4> {

static constexpr gfp zero() noexcept { return {}; }

Expand All @@ -36,8 +36,8 @@ struct gfp : array<uint64_t, 4> {
constexpr gfp mul(const gfp& other) const noexcept { return { gfp_mul(*this, other) }; }

constexpr gfp invert() const noexcept {
constexpr array<uint64_t, 4> bits = { 0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d,
0x30644e72e131a029 };
constexpr std::array<uint64_t, 4> bits = { 0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d,
0x30644e72e131a029 };

gfp sum{ constants::rn1 };
auto power = *this;
Expand Down
36 changes: 18 additions & 18 deletions src/gfp_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,51 @@ namespace bn256 {

namespace constants {
// p2 is p, represented as little-endian 64-bit words.
inline constexpr array<uint64_t, 4> p2 = { 0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d,
0x30644e72e131a029 };
inline constexpr std::array<uint64_t, 4> p2 = { 0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d,
0x30644e72e131a029 };

// np is the negative inverse of p, mod 2^256.
inline constexpr array<uint64_t, 4> np = { 0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80,
0xf57a22b791888c6b };
inline constexpr std::array<uint64_t, 4> np = { 0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80,
0xf57a22b791888c6b };

} // namespace constants

constexpr array<uint64_t, 4> gfp_carry(const array<uint64_t, 4>& a, uint64_t head) noexcept {
array<uint64_t, 4> b{};
constexpr std::array<uint64_t, 4> gfp_carry(const std::array<uint64_t, 4>& a, uint64_t head) noexcept {
std::array<uint64_t, 4> b{};

bool carry = subborrow_u256(false, a.data(), constants::p2.data(), b.data());
carry = subborrow_u64(carry, head, 0, &head);

return carry ? a : b;
}

constexpr array<uint64_t, 4> gfp_neg(const array<uint64_t, 4>& a) noexcept {
array<uint64_t, 4> b{};
constexpr std::array<uint64_t, 4> gfp_neg(const std::array<uint64_t, 4>& a) noexcept {
std::array<uint64_t, 4> b{};
subborrow_u256(false, constants::p2.data(), a.data(), b.data());
return gfp_carry(b, 0);
}

constexpr array<uint64_t, 4> gfp_add(const array<uint64_t, 4>& a, const array<uint64_t, 4>& b) noexcept {
array<uint64_t, 4> c{};
constexpr std::array<uint64_t, 4> gfp_add(const std::array<uint64_t, 4>& a, const std::array<uint64_t, 4>& b) noexcept {
std::array<uint64_t, 4> c{};
bool carry = addcarry_u256(false, a.data(), b.data(), c.data());
return gfp_carry(c, carry);
}

constexpr array<uint64_t, 4> gfp_sub(const array<uint64_t, 4>& a, const array<uint64_t, 4>& b) noexcept {
array<uint64_t, 4> t{};
constexpr std::array<uint64_t, 4> gfp_sub(const std::array<uint64_t, 4>& a, const std::array<uint64_t, 4>& b) noexcept {
std::array<uint64_t, 4> t{};
subborrow_u256(false, constants::p2.data(), b.data(), t.data());
array<uint64_t, 4> c{};
std::array<uint64_t, 4> c{};
uint64_t carry = addcarry_u256(false, a.data(), t.data(), c.data());
return gfp_carry(c, carry);
}

[[gnu::hot]]
constexpr array<uint64_t, 4> gfp_mul(const array<uint64_t, 4>& a, const array<uint64_t, 4>& b) noexcept {
array<uint64_t, 8> T = {};
constexpr std::array<uint64_t, 4> gfp_mul(const std::array<uint64_t, 4>& a, const std::array<uint64_t, 4>& b) noexcept {
std::array<uint64_t, 8> T = {};
full_mul_u256(a.data(), b.data(), T.data());
array<uint64_t, 4> m = {};
std::array<uint64_t, 4> m = {};
half_mul_u256(T.data(), constants::np.data(), m.data());
array<uint64_t, 8> t = {};
std::array<uint64_t, 8> t = {};
full_mul_u256(m.data(), constants::p2.data(), t.data());

bool carry = false;
Expand All @@ -60,4 +60,4 @@ constexpr array<uint64_t, 4> gfp_mul(const array<uint64_t, 4>& a, const array<ui
return gfp_carry({ T[4], T[5], T[6], T[7] }, carry);
}

} // namespace bn256
} // namespace bn256
2 changes: 1 addition & 1 deletion src/int512.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace bn256 {
constexpr uint64_t signbits(int64_t a) { return a < 0 ? UINT64_MAX : 0; }

struct int512_t {
array<uint64_t, 8> limbs_;
std::array<uint64_t, 8> limbs_;

constexpr int512_t(int64_t a = 0)
: limbs_{
Expand Down
6 changes: 3 additions & 3 deletions src/lattice.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct lattice {

// decompose takes a scalar mod order as input and finds a short,
// positive decomposition of it wrt to the lattice basis.
constexpr array<int512_t, N> decompose(std::span<const uint64_t, 4> scalar) const noexcept{
constexpr std::array<int512_t, N> decompose(std::span<const uint64_t, 4> scalar) const noexcept{
int512_t k = {scalar[0], scalar[1], scalar[2], scalar[3], 0, 0, 0, 0};
// int512_t k = to_i512(scalar);
int512_t c[N] = {};
Expand All @@ -24,8 +24,8 @@ struct lattice {
}

// Transform vectors according to c and subtract <k,0,0,...>.
array<int512_t, N> out;
int512_t temp;
std::array<int512_t, N> out;
int512_t temp;
for (std::size_t i = 0; i < N; i++) {
out[i] = 0;
for (std::size_t j = 0; j < N; j++) {
Expand Down
9 changes: 5 additions & 4 deletions src/optate.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,10 @@ constexpr void mul_line(gfp12& ret, const gfp2& a, const gfp2& b, const gfp2& c)
}

// sixuPlus2NAF is 6u+2 in non-adjacent form.
constexpr array<int8_t, 65> six_u_plus_2_naf = { 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0,
0, 1, 0, -1, 0, 0, 0, 0, 1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0,
-1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1 };
constexpr std::array<int8_t, 65> six_u_plus_2_naf = {
0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0,
0, 1, 0, -1, 0, 0, 0, 0, 1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0,
-1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1 };

// miller implements the Miller loop for calculating the Optimal Ate pairing.
// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
Expand Down Expand Up @@ -292,4 +293,4 @@ inline gfp12 optimal_ate(const twist_point& a, const curve_point& b) noexcept {
}
return ret;
}
} // namespace bn256
} // namespace bn256
Loading
Loading