This commit is contained in:
Huang-Ming Huang
2022-10-08 11:06:59 -05:00
parent ac5e1423ea
commit e60f9b47af
28 changed files with 1889 additions and 2217 deletions
+76
View File
@@ -0,0 +1,76 @@
BasedOnStyle: LLVM
IndentWidth: 3
UseTab: Never
ColumnLimit: 120
---
Language: Cpp
# always align * and & to the type
DerivePointerAlignment: false
PointerAlignment: Left
# regroup includes to these classes
IncludeCategories:
- Regex: '(<|"(eosio)/)'
Priority: 4
- Regex: '(<|"(boost)/)'
Priority: 3
- Regex: '(<|"(llvm|llvm-c|clang|clang-c)/'
Priority: 3
- Regex: '<[[:alnum:]]+>'
Priority: 2
- Regex: '.*'
Priority: 1
#IncludeBlocks: Regroup
# set indent for public, private and protected
#AccessModifierOffset: 3
# make line continuations twice the normal indent
ContinuationIndentWidth: 6
# add missing namespace comments
FixNamespaceComments: true
# add spaces to braced list i.e. int* foo = { 0, 1, 2 }; instead of int* foo = {0,1,2};
Cpp11BracedListStyle: false
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignOperands: true
AlignTrailingComments: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortBlocksOnASingleLine: true
#AllowShortIfStatementsOnASingleLine: WithoutElse
#AllowShortIfStatementsOnASingleLine: true
#AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakTemplateDeclarations: true
BinPackParameters: true
### use this with clang9
BreakBeforeBraces: Custom
BraceWrapping:
#AfterCaseLabel: true
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BreakConstructorInitializers: BeforeColon
CompactNamespaces: true
IndentCaseLabels: true
IndentPPDirectives: AfterHash
NamespaceIndentation: Inner
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
---
+1 -1
View File
@@ -2,7 +2,7 @@
namespace bn256 {
std::size_t bitlen(const int512_t& value) {
std::size_t bitlen(const int512_t& value) noexcept {
std::size_t len = 0;
auto x = abs(value);
while (x) {
+3 -3
View File
@@ -3,7 +3,7 @@
#include <boost/multiprecision/cpp_int.hpp>
namespace bn256 {
using namespace boost::multiprecision;
using namespace boost::multiprecision;
std::size_t bitlen(const int512_t& value);
}
std::size_t bitlen(const int512_t& value) noexcept;
} // namespace bn256
+236 -302
View File
@@ -1,319 +1,253 @@
#include <bn256.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <curve.h>
#include <optate.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <random_256.h>
#include <sstream>
namespace bn256 {
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
// scalar_base_mult sets g1 to g*k where g is the generator of the group and then
// returns g1.
const g1& g1::scalar_base_mult(const int512_t& k) {
p_.mul(curve_gen, k);
return *this;
}
std::tuple<int512_t, g1> ramdom_g1() {
random_256 rand;
auto k = rand.sample();
return std::tuple(k, g1::scalar_base_mult(k));
}
// scalar_mult sets g1 to a*k and then returns g1.
const g1& g1::scalar_mult(const g1& a, const int512_t& k) {
p_.mul(a.p_, k);
return *this;
}
std::string g1::string() const { return p_.string(); }
// add sets g1 to a+b and then returns g1.
const g1& g1::add(const g1& a, const g1& b) {
p_.add(a.p_, b.p_);
return *this;
}
// scalar_base_mult returns g*k where g is the generator of the group
g1 g1::scalar_base_mult(const int512_t& k) noexcept { return { curve_gen.mul(k) }; }
// neg sets g1 to -a and then returns g1.
const g1& g1::neg(const g1& a) {
p_.neg(a.p_);
return *this;
}
// scalar_mult returns a*k
g1 g1::scalar_mult(const int512_t& k) const noexcept { return { p_.mul(k) }; }
// marshal converts g1 to a byte slice.
void g1::marshal(nonstd::span<uint8_t, 64> m) const {
constexpr auto num_bytes = 256 / 8;
auto affined = p_.make_affine();
if (affined.is_infinity()) {
return;
}
// add sets g1 to a+b and then returns g1.
g1 g1::add(const g1& b) const noexcept { return { p_.add(b.p_) }; }
affined.x_.mont_decode().marshal(m.subspan<0, num_bytes>());
affined.y_.mont_decode().marshal(m.subspan<num_bytes, num_bytes>());
// neg sets g1 to -a and then returns g1.
g1 g1::neg() { return { p_.neg() }; }
// marshal converts g1 to a byte slice.
void g1::marshal(nonstd::span<uint8_t, 64> m) const noexcept {
constexpr auto num_bytes = 256 / 8;
auto affined = p_.make_affine();
if (affined.is_infinity()) {
return;
}
// unmarshal sets g1 to the result of converting the output of marshal back into
// a group element and then returns unmarshal_status.
std::error_code g1::unmarshal(nonstd::span<const uint8_t, 64> m) {
constexpr auto num_bytes = 256 / 8;
g1& e = *this;
if (auto ec = e.p_.x_.unmarshal(m.subspan<0, num_bytes>()); ec)
return ec;
if (auto ec = e.p_.y_.unmarshal(m.subspan<num_bytes, num_bytes>()); ec)
return ec;
e.p_.x_ = e.p_.x_.mont_encode();
e.p_.y_ = e.p_.y_.mont_encode();
constexpr gfp zero{};
if (e.p_.x_ == zero && e.p_.y_ == zero) {
// This is the point at infinity.
e.p_.y_ = new_gfp(1);
e.p_.z_ = zero;
e.p_.t_ = zero;
} else {
e.p_.z_ = new_gfp(1);
e.p_.t_ = new_gfp(1);
if (!e.p_.is_on_curve()) {
return unmarshal_error::MALFORMED_POINT;
}
}
return {};
}
std::string g1::string() const {
std::stringstream ss;
ss << "bn256.g1" << p_.string();
return ss.str();
}
// scalar_base_mult sets g2 to g*k where g is the generator of the group and then
// returns out.
const g2& g2::scalar_base_mult(const int512_t& k) {
p_.mul(twist_gen, k);
return *this;
}
// scalar_mult sets g2 to a*k and then returns g2.
const g2& g2::scalar_mult(const g2& a, const int512_t& k) {
p_.mul(a.p_, k);
return *this;
}
// add sets g2 to a+b and then returns g2.
const g2& g2::add(const g2& a, const g2& b) {
p_.add(a.p_, b.p_);
return *this;
}
// neg sets g2 to -a and then returns g2.
const g2& g2::neg(const g2& a) {
p_.neg(a.p_);
return *this;
}
// marshal converts g2 to a byte slice.
void g2::marshal(nonstd::span<uint8_t, 128> view) const {
constexpr auto num_bytes = 256 / 8;
auto affined = p_.make_affine();
if (affined.is_infinity()) {
return;
}
affined.x_.x_.mont_decode().marshal(view.subspan<0, num_bytes>());
affined.x_.y_.mont_decode().marshal(view.subspan<num_bytes, num_bytes>());
affined.y_.x_.mont_decode().marshal(view.subspan<num_bytes*2, num_bytes>());
affined.y_.y_.mont_decode().marshal(view.subspan<num_bytes*3, num_bytes>());
}
// unmarshal sets g2 to the result of converting the output of marshal back into
// a group element and then returns unmarshal_status.
std::error_code g2::unmarshal(nonstd::span<const uint8_t, 128> m) {
constexpr auto num_bytes = 256 / 8;
if (auto ec = p_.x_.x_.unmarshal(m.subspan<0, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.y_.unmarshal(m.subspan<num_bytes, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.x_.unmarshal(m.subspan<num_bytes*2, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.y_.unmarshal(m.subspan<num_bytes*3, num_bytes>()); ec)
return ec;
p_.x_.x_ = p_.x_.x_.mont_encode();
p_.x_.y_ = p_.x_.y_.mont_encode();
p_.y_.x_ = p_.y_.x_.mont_encode();
p_.y_.y_ = p_.y_.y_.mont_encode();
if (p_.x_.is_zero() && p_.y_.is_zero()) {
// This is the point at infinity.
p_.y_.set_one();
p_.z_.set_zero();
p_.t_.set_zero();
} else {
p_.z_.set_one();
p_.t_.set_one();
if (!p_.is_on_curve()) {
return unmarshal_error::MALFORMED_POINT;
}
}
return {};
}
std::string g2::string() {
std::stringstream ss;
ss << "bn256.g2" << p_.string();
return ss.str();
}
const gt& gt::scalar_mult(const gt& a, const int512_t& k) {
p_.exp(a.p_, k);
return *this;
}
const gt& gt::add(const gt& a, const gt& b) {
p_.mul(a.p_, b.p_);
return *this;
}
const gt& gt::neg(const gt& a) {
p_.conjugate(a.p_);
return *this;
}
const gt& gt::finalize() {
auto ret = final_exponentiation(p_);
p_ = ret;
return *this;
}
void gt::marshal(nonstd::span<uint8_t, 384> m) const {
constexpr auto num_bytes = 256 / 8;
p_.x_.x_.x_.mont_decode().marshal(m.subspan<0, num_bytes>());
p_.x_.x_.y_.mont_decode().marshal(m.subspan<num_bytes, num_bytes>());
p_.x_.y_.x_.mont_decode().marshal(m.subspan<num_bytes*2, num_bytes>());
p_.x_.y_.y_.mont_decode().marshal(m.subspan<num_bytes*3, num_bytes>());
p_.x_.z_.x_.mont_decode().marshal(m.subspan<num_bytes*4, num_bytes>());
p_.x_.z_.y_.mont_decode().marshal(m.subspan<num_bytes*5, num_bytes>());
p_.y_.x_.x_.mont_decode().marshal(m.subspan<num_bytes*6, num_bytes>());
p_.y_.x_.y_.mont_decode().marshal(m.subspan<num_bytes*7, num_bytes>());
p_.y_.y_.x_.mont_decode().marshal(m.subspan<num_bytes*8, num_bytes>());
p_.y_.y_.y_.mont_decode().marshal(m.subspan<num_bytes*9, num_bytes>());
p_.y_.z_.x_.mont_decode().marshal(m.subspan<num_bytes*10, num_bytes>());
p_.y_.z_.y_.mont_decode().marshal(m.subspan<num_bytes*11, num_bytes>());
}
std::error_code gt::unmarshal(nonstd::span<const uint8_t, 384> m) {
constexpr auto num_bytes = 256 / 8;
if (auto ec = p_.x_.x_.x_.unmarshal(m.subspan<0, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.x_.y_.unmarshal(m.subspan<num_bytes, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.y_.x_.unmarshal(m.subspan<num_bytes*2, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.y_.y_.unmarshal(m.subspan<num_bytes*3, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.z_.x_.unmarshal(m.subspan<num_bytes*4, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.z_.y_.unmarshal(m.subspan<num_bytes*5, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.x_.x_.unmarshal(m.subspan<num_bytes*6, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.x_.y_.unmarshal(m.subspan<num_bytes*7, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.y_.x_.unmarshal(m.subspan<num_bytes*8, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.y_.y_.unmarshal(m.subspan<num_bytes*9, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.z_.x_.unmarshal(m.subspan<num_bytes*10, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.z_.y_.unmarshal(m.subspan<num_bytes*11, num_bytes>()); ec)
return ec;
p_.x_.x_.x_ = p_.x_.x_.x_.mont_encode();
p_.x_.x_.y_ = p_.x_.x_.y_.mont_encode();
p_.x_.y_.x_ = p_.x_.y_.x_.mont_encode();
p_.x_.y_.y_ = p_.x_.y_.y_.mont_encode();
p_.x_.z_.x_ = p_.x_.z_.x_.mont_encode();
p_.x_.z_.y_ = p_.x_.z_.y_.mont_encode();
p_.y_.x_.x_ = p_.y_.x_.x_.mont_encode();
p_.y_.x_.y_ = p_.y_.x_.y_.mont_encode();
p_.y_.y_.x_ = p_.y_.y_.x_.mont_encode();
p_.y_.y_.y_ = p_.y_.y_.y_.mont_encode();
p_.y_.z_.x_ = p_.y_.z_.x_.mont_encode();
p_.y_.z_.y_ = p_.y_.z_.y_.mont_encode();
return {};
}
bool gt::operator==(const gt& rhs) const {
return p_ == rhs.p_;
}
bool gt::operator!=(const gt& rhs) const {
return !(rhs == *this);
}
std::string gt::string() {
std::stringstream ss;
ss << "bn256.gt" << p_.string();
return ss.str();
}
// pair calculates an Optimal Ate pairing.
gt pair(const g1& g1, const g2& g2) {
gt ret = {optimal_ate(g2.p_, g1.p_)};
return ret;
}
// pairing_check calculates the Optimal Ate pairing for a set of points.
bool pairing_check(std::vector<g1>& a, std::vector<g2>& b) {
gfp12 acc{};
acc.set_one();
for (auto i = 0; i < a.size(); ++i) {
if (a[i].p_.is_infinity() || b[i].p_.is_infinity()) {
continue;
}
acc.mul(acc, miller(b[i].p_, a[i].p_));
}
return final_exponentiation(acc).is_one();
}
// miller applies Miller's algorithm, which is a bilinear function from
// the source groups to F_p^12. miller(g1, g2).finalize() is equivalent
// to pair(g1,g2).
gt miller(const g1& g1, const g2& g2) {
gt ret = {miller(g2.p_, g1.p_)};
return ret;
}
std::tuple<int512_t, g1> ramdom_g1() {
random_256 rand;
auto k = rand.sample();
g1 ret{};
return std::tuple(k, ret.scalar_base_mult(k));
}
std::tuple<int512_t, g2> ramdom_g2() {
random_256 rand;
g2 ret{};
auto k = rand.sample();
return std::make_tuple(k, ret.scalar_base_mult(k));
}
std::ostream& operator << (std::ostream& os, const gt& v) {
return os << v.p_;
}
affined.x_.mont_decode().marshal(m.subspan<0, num_bytes>());
affined.y_.mont_decode().marshal(m.subspan<num_bytes, num_bytes>());
return;
}
// unmarshal sets g1 to the result of converting the output of marshal back into
// a group element and then returns unmarshal_status.
std::error_code g1::unmarshal(nonstd::span<const uint8_t, 64> m) noexcept {
constexpr auto num_bytes = 256 / 8;
g1& e = *this;
if (auto ec = e.p_.x_.unmarshal(m.subspan<0, num_bytes>()); ec)
return ec;
if (auto ec = e.p_.y_.unmarshal(m.subspan<num_bytes, num_bytes>()); ec)
return ec;
e.p_.x_ = e.p_.x_.mont_encode();
e.p_.y_ = e.p_.y_.mont_encode();
if (e.p_.x_ == gfp::zero() && e.p_.y_ == gfp::zero()) {
// This is the point at infinity.
e.p_.y_ = new_gfp(1);
e.p_.z_ = gfp::zero();
e.p_.t_ = gfp::zero();
} else {
e.p_.z_ = new_gfp(1);
e.p_.t_ = new_gfp(1);
if (!e.p_.is_on_curve()) {
return unmarshal_error::MALFORMED_POINT;
}
}
return {};
}
std::tuple<int512_t, g2> ramdom_g2() {
random_256 rand;
auto k = rand.sample();
return std::make_tuple(k, g2::scalar_base_mult(k));
}
std::string g2::string() const { return p_.string(); }
// scalar_base_mult sets g2 to g*k where g is the generator of the group and then
// returns out.
g2 g2::scalar_base_mult(const int512_t& k) noexcept { return { twist_gen.mul(k) }; }
// scalar_mult sets g2 to a*k and then returns g2.
g2 g2::scalar_mult(const int512_t& k) const noexcept { return { p_.mul(k) }; }
// add sets g2 to a+b and then returns g2.
g2 g2::add(const g2& b) const noexcept { return { p_.add(b.p_) }; }
// neg sets g2 to -a and then returns g2.
g2 g2::neg() const noexcept { return { p_.neg() }; }
// marshal converts g2 to a byte slice.
void g2::marshal(nonstd::span<uint8_t, 128> view) const noexcept {
constexpr auto num_bytes = 256 / 8;
auto affined = p_.make_affine();
if (affined.is_infinity()) {
return;
}
affined.x_.x_.mont_decode().marshal(view.subspan<0, num_bytes>());
affined.x_.y_.mont_decode().marshal(view.subspan<num_bytes, num_bytes>());
affined.y_.x_.mont_decode().marshal(view.subspan<num_bytes * 2, num_bytes>());
affined.y_.y_.mont_decode().marshal(view.subspan<num_bytes * 3, num_bytes>());
}
// unmarshal sets g2 to the result of converting the output of marshal back into
// a group element and then returns unmarshal_status.
std::error_code g2::unmarshal(nonstd::span<const uint8_t, 128> m) noexcept {
constexpr auto num_bytes = 256 / 8;
if (auto ec = p_.x_.x_.unmarshal(m.subspan<0, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.y_.unmarshal(m.subspan<num_bytes, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.x_.unmarshal(m.subspan<num_bytes * 2, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.y_.unmarshal(m.subspan<num_bytes * 3, num_bytes>()); ec)
return ec;
p_.x_.x_ = p_.x_.x_.mont_encode();
p_.x_.y_ = p_.x_.y_.mont_encode();
p_.y_.x_ = p_.y_.x_.mont_encode();
p_.y_.y_ = p_.y_.y_.mont_encode();
if (p_.x_.is_zero() && p_.y_.is_zero()) {
// This is the point at infinity.
p_.y_.set_one();
p_.z_.set_zero();
p_.t_.set_zero();
} else {
p_.z_.set_one();
p_.t_.set_one();
if (!p_.is_on_curve()) {
return unmarshal_error::MALFORMED_POINT;
}
}
return {};
}
std::string gt::string() const { return p_.string(); }
// scalar_mult return a*k
gt gt::scalar_mult(const int512_t& k) const noexcept { return { p_.exp(k) }; }
// add sets gt to a+b and then returns gt.
gt gt::add(const gt& b) const noexcept { return { p_.mul(b.p_) }; }
// neg sets g2 to -a and then returns g2.
gt gt::neg() const noexcept { return { p_.conjugate() }; }
// finalize is a linear function from F_p^12 to gt.
gt gt::finalize() const noexcept { return { final_exponentiation(p_) }; }
void gt::marshal(nonstd::span<uint8_t, 384> m) const noexcept {
constexpr auto num_bytes = 256 / 8;
p_.x_.x_.x_.mont_decode().marshal(m.subspan<0, num_bytes>());
p_.x_.x_.y_.mont_decode().marshal(m.subspan<num_bytes, num_bytes>());
p_.x_.y_.x_.mont_decode().marshal(m.subspan<num_bytes * 2, num_bytes>());
p_.x_.y_.y_.mont_decode().marshal(m.subspan<num_bytes * 3, num_bytes>());
p_.x_.z_.x_.mont_decode().marshal(m.subspan<num_bytes * 4, num_bytes>());
p_.x_.z_.y_.mont_decode().marshal(m.subspan<num_bytes * 5, num_bytes>());
p_.y_.x_.x_.mont_decode().marshal(m.subspan<num_bytes * 6, num_bytes>());
p_.y_.x_.y_.mont_decode().marshal(m.subspan<num_bytes * 7, num_bytes>());
p_.y_.y_.x_.mont_decode().marshal(m.subspan<num_bytes * 8, num_bytes>());
p_.y_.y_.y_.mont_decode().marshal(m.subspan<num_bytes * 9, num_bytes>());
p_.y_.z_.x_.mont_decode().marshal(m.subspan<num_bytes * 10, num_bytes>());
p_.y_.z_.y_.mont_decode().marshal(m.subspan<num_bytes * 11, num_bytes>());
}
std::error_code gt::unmarshal(nonstd::span<const uint8_t, 384> m) noexcept {
constexpr auto num_bytes = 256 / 8;
if (auto ec = p_.x_.x_.x_.unmarshal(m.subspan<0, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.x_.y_.unmarshal(m.subspan<num_bytes, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.y_.x_.unmarshal(m.subspan<num_bytes * 2, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.y_.y_.unmarshal(m.subspan<num_bytes * 3, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.z_.x_.unmarshal(m.subspan<num_bytes * 4, num_bytes>()); ec)
return ec;
if (auto ec = p_.x_.z_.y_.unmarshal(m.subspan<num_bytes * 5, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.x_.x_.unmarshal(m.subspan<num_bytes * 6, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.x_.y_.unmarshal(m.subspan<num_bytes * 7, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.y_.x_.unmarshal(m.subspan<num_bytes * 8, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.y_.y_.unmarshal(m.subspan<num_bytes * 9, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.z_.x_.unmarshal(m.subspan<num_bytes * 10, num_bytes>()); ec)
return ec;
if (auto ec = p_.y_.z_.y_.unmarshal(m.subspan<num_bytes * 11, num_bytes>()); ec)
return ec;
p_.x_.x_.x_ = p_.x_.x_.x_.mont_encode();
p_.x_.x_.y_ = p_.x_.x_.y_.mont_encode();
p_.x_.y_.x_ = p_.x_.y_.x_.mont_encode();
p_.x_.y_.y_ = p_.x_.y_.y_.mont_encode();
p_.x_.z_.x_ = p_.x_.z_.x_.mont_encode();
p_.x_.z_.y_ = p_.x_.z_.y_.mont_encode();
p_.y_.x_.x_ = p_.y_.x_.x_.mont_encode();
p_.y_.x_.y_ = p_.y_.x_.y_.mont_encode();
p_.y_.y_.x_ = p_.y_.y_.x_.mont_encode();
p_.y_.y_.y_ = p_.y_.y_.y_.mont_encode();
p_.y_.z_.x_ = p_.y_.z_.x_.mont_encode();
p_.y_.z_.y_ = p_.y_.z_.y_.mont_encode();
return {};
}
// pair calculates an Optimal Ate pairing.
gt pair(const g1& g1, const g2& g2) noexcept { return { optimal_ate(g2.p_, g1.p_) }; }
// pairing_check calculates the Optimal Ate pairing for a set of points.
bool pairing_check(std::vector<g1>& a, std::vector<g2>& b) noexcept {
gfp12 acc{};
acc.set_one();
for (auto i = 0; i < a.size(); ++i) {
if (a[i].p_.is_infinity() || b[i].p_.is_infinity()) {
continue;
}
acc = acc.mul(miller(b[i].p_, a[i].p_));
}
return final_exponentiation(acc).is_one();
}
// miller applies Miller's algorithm, which is a bilinear function from
// the source groups to F_p^12. miller(g1, g2).finalize() is equivalent
// to pair(g1,g2).
gt miller(const g1& g1, const g2& g2) noexcept { return { miller(g2.p_, g1.p_) }; }
std::ostream& operator<<(std::ostream& os, const gt& v) { return os << v.p_; }
} // namespace bn256
+93 -104
View File
@@ -18,148 +18,137 @@
// However, recent improvements in attacks mean that is no longer true. See
// https://moderncrypto.org/mail-archive/curves/2016/000740.html.)
#include <curve.h>
#include <twist.h>
#include <gfp12.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <curve.h>
#include <gfp12.h>
#include <twist.h>
#include <utility>
using boost::multiprecision::int512_t;
namespace bn256 {
// curveGen is the generator of G₁.
const curve_point curve_gen = {
new_gfp(1),
new_gfp(2),
new_gfp(1),
new_gfp(1)
};
// curveGen is the generator of G₁.
const curve_point curve_gen = { new_gfp(1), new_gfp(2), new_gfp(1), new_gfp(1) };
static const twist_point twist_gen = {
{
{0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b},
{0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b},
},{
{0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482},
{0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206},
},
{new_gfp(0), new_gfp(1)},
{new_gfp(0), new_gfp(1)}
};
static const twist_point twist_gen = {
{
{ 0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b },
{ 0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b },
},
{
{ 0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482 },
{ 0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206 },
},
{ new_gfp(0), new_gfp(1) },
{ new_gfp(0), new_gfp(1) }
};
typedef std::array<uint8_array_32_t, 2> uint8_array_32_array_2_t;
typedef std::array<uint8_array_32_t, 4> uint8_array_32_array_4_t;
typedef std::array<uint8_array_32_t, 12> uint8_array_32_array_12_t;
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
struct g1 {
curve_point p_;
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
struct g1 {
curve_point p_ {};
static g1 scalar_base_mult(const int512_t& k) noexcept;
const g1& scalar_base_mult(const int512_t& k);
g1 scalar_mult(const int512_t& k) const noexcept;
const g1& scalar_mult(const g1& a, const int512_t& k);
g1 add(const g1& b) const noexcept;
const g1& add(const g1& a, const g1& b);
g1 neg();
const g1& neg(const g1& a);
void marshal(nonstd::span<uint8_t,64> out) const;
std::array<uint8_t, 64> marshal() const {
std::array<uint8_t, 64> result;
marshal(result);
return result;
}
[[nodiscard]] std::error_code unmarshal(nonstd::span<const uint8_t,64> in);
std::string string() const;
};
inline std::ostream& operator << (std::ostream& os, const g1& v) {
return os << v.p_.string();
void marshal(nonstd::span<uint8_t, 64> out) const noexcept;
std::array<uint8_t, 64> marshal() const noexcept {
std::array<uint8_t, 64> result;
marshal(result);
return result;
}
// g2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
struct g2 {
twist_point p_ {};
[[nodiscard]] std::error_code unmarshal(nonstd::span<const uint8_t, 64> in) noexcept;
const g2& scalar_base_mult(const int512_t& k);
bool operator==(const g1& rhs) const noexcept { return p_ == rhs.p_; }
bool operator!=(const g1& rhs) const noexcept { return !(*this == rhs); }
const g2& scalar_mult(const g2& a, const int512_t& k);
std::string string() const;
};
const g2& add(const g2& a, const g2& b);
inline std::ostream& operator<<(std::ostream& os, const g1& v) { return os << v.p_.string(); }
const g2& neg(const g2& a);
// g2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
struct g2 {
twist_point p_;
void marshal(nonstd::span<uint8_t,128> out) const;
std::array<uint8_t, 128> marshal() const {
std::array<uint8_t, 128> result;
marshal(result);
return result;
}
static g2 scalar_base_mult(const int512_t& k) noexcept;
[[nodiscard]] std::error_code unmarshal(nonstd::span<const uint8_t,128> m);
g2 scalar_mult(const int512_t& k) const noexcept;
std::string string();
};
g2 add(const g2& b) const noexcept;
inline std::ostream& operator << (std::ostream& os, const g2& v) {
return os << v.p_.string();
g2 neg() const noexcept;
void marshal(nonstd::span<uint8_t, 128> out) const noexcept;
std::array<uint8_t, 128> marshal() const noexcept {
std::array<uint8_t, 128> result;
marshal(result);
return result;
}
// GT is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
struct gt {
gfp12 p_ {};
[[nodiscard]] std::error_code unmarshal(nonstd::span<const uint8_t, 128> m) noexcept;
// scalar_mult sets gt to a*k and then returns gt.
const gt& scalar_mult(const gt& a, const int512_t& k);
bool operator==(const g2& rhs) const noexcept { return p_ == rhs.p_; }
bool operator!=(const g2& rhs) const noexcept { return !(*this == rhs); }
// add sets gt to a+b and then returns gt.
const gt& add(const gt& a, const gt& b);
std::string string() const;
};
// neg sets g2 to -a and then returns g2.
const gt& neg(const gt& a);
inline std::ostream& operator<<(std::ostream& os, const g2& v) { return os << v.p_.string(); }
// finalize is a linear function from F_p^12 to gt.
const gt& finalize();
// GT is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
struct gt {
gfp12 p_;
// marshal converts g2 to a byte slice.
void marshal(nonstd::span<uint8_t, 384> out) const;
std::array<uint8_t, 384> marshal() const {
std::array<uint8_t, 384> result;
marshal(result);
return result;
}
gt scalar_mult(const int512_t& k) const noexcept;
// unmarshal sets gt to the result of converting the output of marshal back into
// a group element and then returns unmarshal_status.
[[nodiscard]] std::error_code unmarshal(nonstd::span<const uint8_t, 384> m);
gt add(const gt& b) const noexcept ;
bool operator==(const gt& rhs) const;
gt neg() const noexcept;
bool operator!=(const gt& rhs) const;
gt finalize() const noexcept;
std::string string();
};
// marshal converts g2 to a byte slice.
void marshal(nonstd::span<uint8_t, 384> out) const noexcept;
std::array<uint8_t, 384> marshal() const noexcept {
std::array<uint8_t, 384> result;
marshal(result);
return result;
}
std::ostream& operator << (std::ostream& os, const gt& v);
// unmarshal sets gt to the result of converting the output of marshal back into
// a group element and then returns unmarshal_status.
[[nodiscard]] std::error_code unmarshal(nonstd::span<const uint8_t, 384> m) noexcept;
// pair calculates an Optimal Ate pairing.
gt pair(const g1& g1, const g2& g2);
bool operator==(const gt& rhs) const noexcept { return p_ == rhs.p_; }
bool operator!=(const gt& rhs) const noexcept { return !(*this == rhs); }
// pairing_check calculates the Optimal Ate pairing for a set of points.
bool pairing_check(std::vector<g1>& a, std::vector<g2>& b);
std::string string() const;
};
// miller applies Miller's algorithm, which is a bilinear function from
// the source groups to F_p^12. miller(g1, g2).finalize() is equivalent
// to pair(g1,g2).
gt miller(const g1& g1, const g2& g2);
std::ostream& operator<<(std::ostream& os, const gt& v);
std::tuple<int512_t,g1> ramdom_g1();
std::tuple<int512_t,g2> ramdom_g2();
// pair calculates an Optimal Ate pairing.
gt pair(const g1& g1, const g2& g2) noexcept;
}
// pairing_check calculates the Optimal Ate pairing for a set of points.
bool pairing_check(std::vector<g1>& a, std::vector<g2>& b) noexcept;
// miller applies Miller's algorithm, which is a bilinear function from
// the source groups to F_p^12. miller(g1, g2).finalize() is equivalent
// to pair(g1,g2).
gt miller(const g1& g1, const g2& g2) noexcept;
std::tuple<int512_t, g1> ramdom_g1();
std::tuple<int512_t, g2> ramdom_g2();
} // namespace bn256
+56 -76
View File
@@ -1,98 +1,78 @@
#pragma once
#include <boost/multiprecision/cpp_int.hpp>
#include <gfp.h>
#include <gfp2.h>
#include <gfp6.h>
#include <boost/multiprecision/cpp_int.hpp>
namespace bn256::constants {
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
// u is the BN parameter.
inline constexpr int512_t u = 0x44E992B44A6909F1_cppi512;
// u is the BN parameter.
inline constexpr int512_t u = 0x44E992B44A6909F1_cppi512;
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
// Needs to be highly 2-adic for efficient SNARK key and proof generation.
// Order - 1 = 2^28 * 3^2 * 13 * 29 * 983 * 11003 * 237073 * 405928799 * 1670836401704629 * 13818364434197438864469338081.
// Refer to https://eprint.iacr.org/2013/879.pdf and https://eprint.iacr.org/2013/507.pdf for more information on these parameters.
// order is 21888242871839275222246405745257275088548364400416034343698204186575808495617 dec 254 bits
inline constexpr int512_t order = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001_cppi512;
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
// Needs to be highly 2-adic for efficient SNARK key and proof generation.
// Order - 1 = 2^28 * 3^2 * 13 * 29 * 983 * 11003 * 237073 * 405928799 * 1670836401704629 *
// 13818364434197438864469338081. Refer to https://eprint.iacr.org/2013/879.pdf and https://eprint.iacr.org/2013/507.pdf
// for more information on these parameters. order is
// 21888242871839275222246405745257275088548364400416034343698204186575808495617 dec 254 bits
inline constexpr int512_t order = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001_cppi512;
// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
// p is 21888242871839275222246405745257275088696311157297823662689037894645226208583 dec 254 bits
inline constexpr int512_t p = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD47_cppi512;
// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
// p is 21888242871839275222246405745257275088696311157297823662689037894645226208583 dec 254 bits
inline constexpr int512_t p = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD47_cppi512;
// p2 is p, represented as little-endian 64-bit words.
inline constexpr gfp p2 = {
0x3c208c16d87cfd47,
0x97816a916871ca8d,
0xb85045b68181585d,
0x30644e72e131a029
};
// p2 is p, represented as little-endian 64-bit words.
inline constexpr gfp p2 = { 0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029 };
// np is the negative inverse of p, mod 2^256.
inline constexpr uint64_array_4_t np = {
0x87d20782e4866389,
0x9ede7d651eca6ac9,
0xd8afcbd01833da80,
0xf57a22b791888c6b
};
// np is the negative inverse of p, mod 2^256.
inline constexpr uint64_array_4_t np = { 0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80,
0xf57a22b791888c6b };
// rn1 is R^-1 where R = 2^256 mod p.
inline constexpr gfp rn1 = {0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639};
// rn1 is R^-1 where R = 2^256 mod p.
inline constexpr gfp rn1 = { 0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639 };
// r2 is R^2 where R = 2^256 mod p.
inline constexpr gfp r2 = {0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f};
// r2 is R^2 where R = 2^256 mod p.
inline constexpr gfp r2 = { 0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f };
// r3 is R^3 where R = 2^256 mod p.
inline constexpr gfp r3 = {0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544};
// r3 is R^3 where R = 2^256 mod p.
inline constexpr gfp r3 = { 0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544 };
// xi_to_p_minus_1_over_6 is ξ^((p-1)/6) where ξ = i+9.
inline constexpr gfp2 xi_to_p_minus_1_over_6 = {
{0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551},
{0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c}
};
// xi_to_p_minus_1_over_6 is ξ^((p-1)/6) where ξ = i+9.
inline constexpr gfp2 xi_to_p_minus_1_over_6 = {
{ 0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551 },
{ 0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c }
};
// xi_to_p_minus_1_over_3 is ξ^((p-1)/3) where ξ = i+9.
inline constexpr gfp2 xi_to_p_minus_1_over_3 = {
{0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3},
{0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec}
};
// xi_to_p_minus_1_over_3 is ξ^((p-1)/3) where ξ = i+9.
inline constexpr gfp2 xi_to_p_minus_1_over_3 = {
{ 0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3 },
{ 0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec }
};
// xi_to_p_minus_1_over_2 is ξ^((p-1)/2) where ξ = i+9.
inline constexpr gfp2 xi_to_p_minus_1_over_2 = {
{0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc},
{0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd}
};
// xi_to_p_minus_1_over_2 is ξ^((p-1)/2) where ξ = i+9.
inline constexpr gfp2 xi_to_p_minus_1_over_2 = {
{ 0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc },
{ 0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd }
};
// xi_to_p_squared_minus_1_over_3 is ξ^((p²-1)/3) where ξ = i+9.
inline constexpr gfp xi_to_p_squared_minus_1_over_3 = {
0x3350c88e13e80b9c,
0x7dce557cdb5e56b9,
0x6001b4b8b615564a,
0x2682e617020217e0
};
// xi_to_p_squared_minus_1_over_3 is ξ^((p²-1)/3) where ξ = i+9.
inline constexpr gfp xi_to_p_squared_minus_1_over_3 = { 0x3350c88e13e80b9c, 0x7dce557cdb5e56b9, 0x6001b4b8b615564a,
0x2682e617020217e0 };
// xi_to_2p_squared_minus_2_over_3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
inline constexpr gfp xi_to_2p_squared_minus_2_over_3 = {
0x71930c11d782e155,
0xa6bb947cffbe3323,
0xaa303344d4741444,
0x2c3b3f0d26594943
};
// xi_to_2p_squared_minus_2_over_3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
inline constexpr gfp xi_to_2p_squared_minus_2_over_3 = { 0x71930c11d782e155, 0xa6bb947cffbe3323, 0xaa303344d4741444,
0x2c3b3f0d26594943 };
// xi_to_p_squared_minus_1_over_6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p).
inline constexpr gfp xi_to_p_squared_minus_1_over_6 = {
0xca8d800500fa1bf2,
0xf0c5d61468b39769,
0x0e201271ad0d4418,
0x04290f65bad856e6
};
// xi_to_p_squared_minus_1_over_6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p).
inline constexpr gfp xi_to_p_squared_minus_1_over_6 = { 0xca8d800500fa1bf2, 0xf0c5d61468b39769, 0x0e201271ad0d4418,
0x04290f65bad856e6 };
// xi_to_2p_minus_2_over_3 is ξ^((2p-2)/3) where ξ = i+9.
inline constexpr gfp2 xi_to_2p_minus_2_over_3 = {
{0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd},
{0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec}
};
}
// xi_to_2p_minus_2_over_3 is ξ^((2p-2)/3) where ξ = i+9.
inline constexpr gfp2 xi_to_2p_minus_2_over_3 = {
{ 0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd },
{ 0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec }
};
} // namespace bn256::constants
+195 -217
View File
@@ -1,229 +1,207 @@
#include <constants.h>
#include <curve.h>
#include <gfp_generic.h>
#include <constants.h>
#include <lattice.h>
using boost::multiprecision::int512_t;
namespace bn256 {
static const gfp curve_b = new_gfp(3);
static const gfp curve_b = new_gfp(3);
std::string curve_point::string() const {
auto tmp = make_affine();
std::string curve_point::string() const {
auto tmp = make_affine();
gfp x{}, y{};
x = tmp.x_.mont_decode();
y = tmp.y_.mont_decode();
gfp x = tmp.x_.mont_decode();
gfp y = tmp.y_.mont_decode();
std::string ret;
ret.reserve(132);
ret.append("(");
ret.append(x.string());
ret.append(", ");
ret.append(y.string());
ret.append(")");
std::string ret;
ret.reserve(132);
ret.append("(");
ret.append(x.string());
ret.append(",");
ret.append(y.string());
ret.append(")");
return ret;
}
bool curve_point::is_on_curve() const {
auto tmp = make_affine();
if (tmp.is_infinity()) {
return true;
}
gfp y2{}, x3{};
gfp_mul(y2, tmp.y_, tmp.y_);
gfp_mul(x3, tmp.x_, tmp.x_);
gfp_mul(x3, x3, tmp.x_);
gfp_add(x3, x3, curve_b);
return y2 == x3;
}
void curve_point::set_infinity() {
x_.fill(0);
y_ = new_gfp(1ll);
z_.fill(0);
t_.fill(0);
}
bool curve_point::is_infinity() const {
constexpr gfp gfp_infinity{};
return z_ == gfp_infinity;
}
void curve_point::add(const curve_point& a, const curve_point& b) {
if (a.is_infinity()) {
*this = b;
return;
}
if (b.is_infinity()) {
*this = a;
return;
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
gfp z12{}, z22{};
gfp_mul(z12, a.z_, a.z_);
gfp_mul(z22, b.z_, b.z_);
gfp u1{}, u2{};
gfp_mul(u1, a.x_, z22);
gfp_mul(u2, b.x_, z12);
gfp t{}, s1{};
gfp_mul(t, b.z_, z22);
gfp_mul(s1, a.y_, t);
gfp s2{};
gfp_mul(t, a.z_, z12);
gfp_mul(s2, b.y_, t);
// Compute x_ = (2h)²(s²-u1-u2)
// where s = (s2-s1)/(u2-u1) is the slope of the line through
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z_ below.
// This is also:
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
// = r² - j - 2v
// with the notations below.
gfp h{};
gfp_sub(h, u2, u1);
constexpr gfp gfp_zero{};
bool x_equal = (h == gfp_zero);
gfp_add(t, h, h);
// i = 4h²
gfp i{};
gfp_mul(i, t, t);
// j = 4h³
gfp j{};
gfp_mul(j, h, i);
gfp_sub(t, s2, s1);
bool y_equal = (t == gfp_zero);
if (x_equal && y_equal) {
double_(a);
return;
}
gfp r{};
gfp_add(r, t, t);
gfp v{};
gfp_mul(v, u1, i);
// t4 = 4(s2-s1)²
gfp t4{}, t6{};
gfp_mul(t4, r, r);
gfp_add(t, v, v);
gfp_sub(t6, t4, j);
gfp_sub(x_, t6, t);
// Set y_ = -(2h)³(s1 + s*(x_/4h²-u1))
// This is also
// y_ = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x_) - 2·s1·j
gfp_sub(t, v, x_); // t7
gfp_mul(t4, s1, j); // t8
gfp_add(t6, t4, t4); // t9
gfp_mul(t4, r, t); // t10
gfp_sub(y_, t4, t6);
// Set z_ = 2(u2-u1)·z1·z2 = 2h·z1·z2
gfp_add(t, a.z_, b.z_); // t11
gfp_mul(t4, t, t); // t12
gfp_sub(t, t4, z12); // t13
gfp_sub(t4, t, z22); // t14
gfp_mul(z_, t4, h);
}
void curve_point::double_(const curve_point& point) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
gfp a{}, b{}, c{}, d{}, e{}, f{}, t{}, t2{};
gfp_mul(a, point.x_, point.x_);
gfp_mul(b, point.y_, point.y_);
gfp_mul(c, b, b);
gfp_add(t, point.x_, b);
gfp_mul(t2, t, t);
gfp_sub(t, t2, a);
gfp_sub(t2, t, c);
gfp_add(d, t2, t2);
gfp_add(t, a, a);
gfp_add(e, t, a);
gfp_mul(f, e, e);
gfp_add(t, d, d);
gfp_sub(x_, f, t);
gfp_mul(z_, point.y_, point.z_);
gfp_add(z_, z_, z_);
gfp_add(t, c, c);
gfp_add(t2, t, t);
gfp_add(t, t2, t2);
gfp_sub(y_, d, x_);
gfp_mul(t2, e, y_);
gfp_sub(y_, t2, t);
}
void curve_point::mul(const curve_point& a, const int512_t& scalar) {
typedef std::array<curve_point, 4> curve_point_array_4_t;
curve_point_array_4_t precomp{};
precomp[1] = a;
precomp[2] = a;
gfp_mul(precomp[2].x_, precomp[2].x_, constants::xi_to_2p_squared_minus_2_over_3);
precomp[3].add(precomp[1], precomp[2]);
const auto multi_scalar = curve_lattice.multi(scalar);
curve_point sum{};
sum.set_infinity();
curve_point t{};
for (int i = multi_scalar.size() - 1; i >= 0; i--) {
t.double_(sum);
if (multi_scalar[i] == 0) {
sum = t;
} else {
sum.add(t, precomp[multi_scalar[i]]);
}
}
*this = sum;
}
curve_point curve_point::make_affine() const {
if (z_ == new_gfp(1ll)) {
return *this;
} else if (z_ == new_gfp(0ll)) {
return { {}, new_gfp(1ll), new_gfp(0ll), {} };
}
curve_point result{x_, y_, new_gfp(1ll) , new_gfp(1ll)};
gfp z_inv{};
z_inv = z_.invert();
gfp t{}, z_inv2{};
gfp_mul(t, y_, z_inv);
gfp_mul(z_inv2, z_inv, z_inv);
gfp_mul(result.x_, x_, z_inv2);
gfp_mul(result.y_, t, z_inv2);
return result;
}
void curve_point::neg(const curve_point& a) {
x_ = a.x_;
gfp_neg(y_, a.y_);
z_ = a.z_;
t_ = a.t_;
}
return ret;
}
bool curve_point::is_on_curve() const noexcept {
auto c = make_affine();
if (c.is_infinity()) {
return true;
}
gfp y2 = c.y_.mul(c.y_);
gfp x3 = c.x_.mul(c.x_);
x3 = x3.mul(c.x_);
x3 = x3.add(curve_b);
return y2 == x3;
}
curve_point curve_point::add(const curve_point& b) const noexcept {
const curve_point& a = *this;
if (a.is_infinity()) {
return b;
}
if (b.is_infinity()) {
return a;
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
gfp z12 = a.z_.mul(a.z_);
gfp z22 = b.z_.mul(b.z_);
gfp u1 = a.x_.mul(z22);
gfp u2 = b.x_.mul(z12);
gfp t = b.z_.mul(z22);
gfp s1 = a.y_.mul(t);
t = a.z_.mul(z12);
gfp s2 = b.y_.mul(t);
// Compute x_ = (2h)²(s²-u1-u2)
// where s = (s2-s1)/(u2-u1) is the slope of the line through
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z_ below.
// This is also:
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
// = r² - j - 2v
// with the notations below.
gfp h = u2.sub(u1);
bool x_equal = h == gfp{ 0 };
t = h.add(h);
// i = 4h²
gfp i = t.mul(t);
// j = 4h³
gfp j = h.mul(i);
t = s2.sub(s1);
bool y_equal = t == gfp{ 0 };
if (x_equal && y_equal) {
return a.double_();
}
gfp r = t.add(t);
gfp v = u1.mul(i);
// t4 = 4(s2-s1)²
gfp t4 = r.mul(r);
t = v.add(v);
gfp t6 = t4.sub(j);
curve_point c;
c.x_ = t6.sub(t);
// Set y_ = -(2h)³(s1 + s*(x_/4h²-u1))
// This is also
// y_ = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x_) - 2·s1·j
t = v.sub(c.x_); // t7
t4 = s1.mul(j); // t8
t6 = t4.add(t4); // t9
t4 = r.mul(t); // t10
c.y_ = t4.sub(t6);
// Set z_ = 2(u2-u1)·z1·z2 = 2h·z1·z2
t = a.z_.add(b.z_); // t11
t4 = t.mul(t); // t12
t = t4.sub(z12); // t13
t4 = t.sub(z22); // t14
c.z_ = t4.mul(h);
c.t_ = {};
return c;
}
curve_point curve_point::double_() const noexcept {
const curve_point& a = *this;
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
gfp A = a.x_.mul(a.x_);
gfp B = a.y_.mul(a.y_);
gfp C = B.mul(B);
gfp t = a.x_.add(B);
gfp t2 = t.mul(t);
t = t2.sub(A);
t2 = t.sub(C);
gfp d = t2.add(t2);
t = A.add(A);
gfp e = t.add(A);
gfp f = e.mul(e);
t = d.add(d);
curve_point c;
c.x_ = f.sub(t);
c.z_ = a.y_.mul(a.z_);
c.z_ = c.z_.add(c.z_);
t = C.add(C);
t2 = t.add(t);
t = t2.add(t2);
c.y_ = d.sub(c.x_);
t2 = e.mul(c.y_);
c.y_ = t2.sub(t);
c.t_ = {};
return c;
}
curve_point curve_point::mul(const int512_t& scalar) const noexcept {
const curve_point& a = *this;
std::array<curve_point, 4> precomp{};
precomp[1] = a;
precomp[2] = a;
precomp[2].x_ = precomp[2].x_.mul(constants::xi_to_2p_squared_minus_2_over_3);
precomp[3] = precomp[1].add(precomp[2]);
const auto multi_scalar = curve_lattice.multi(scalar);
auto sum = curve_point::infinity;
curve_point t;
for (int i = multi_scalar.size() - 1; i >= 0; i--) {
t = sum.double_();
if (multi_scalar[i] == 0) {
sum = t;
} else {
sum = t.add(precomp[multi_scalar[i]]);
}
}
return sum;
}
curve_point curve_point::make_affine() const noexcept {
if (z_ == new_gfp(1)) {
return *this;
} else if (z_ == new_gfp(0)) {
return { { 0 }, new_gfp(1ll), new_gfp(0), { 0 } };
}
curve_point c{ x_, y_, new_gfp(1), new_gfp(1) };
gfp z_inv = z_.invert();
gfp t = c.y_.mul(z_inv);
gfp z_inv2 = z_inv.mul(z_inv);
c.x_ = c.x_.mul(z_inv2);
c.y_ = t.mul(z_inv2);
return c;
}
curve_point curve_point::neg() const noexcept {
const curve_point& a = *this;
return { a.x_, a.y_.neg(), a.z_, gfp{ 0 } };
}
} // namespace bn256
+30 -24
View File
@@ -1,41 +1,47 @@
#pragma once
#include <gfp.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <gfp.h>
using boost::multiprecision::int512_t;
namespace bn256 {
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian
// form and t=z² when valid. G₁ is the set of points of this curve on GF(p).
struct curve_point {
// value is xτ² + yτ + z
gfp x_;
gfp y_;
gfp z_;
gfp t_;
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian
// form and t=z² when valid. G₁ is the set of points of this curve on GF(p).
struct curve_point {
// value is xτ² + yτ + z
gfp x_;
gfp y_;
gfp z_;
gfp t_;
std::string string() const ;
// IsOnCurve returns true iff c is on the curve.
bool is_on_curve() const;
std::string string() const;
// IsOnCurve returns true iff c is on the curve.
bool is_on_curve() const noexcept;
void set_infinity();
static const curve_point infinity;
bool is_infinity() const noexcept { return z_ == gfp{ 0 }; }
[[nodiscard]] bool is_infinity() const;
curve_point add(const curve_point& b) const noexcept;
void add(const curve_point& a, const curve_point& b);
curve_point double_() const noexcept;
void double_(const curve_point& point);
curve_point mul(const int512_t& scalar) const noexcept;
void mul(const curve_point& a, const int512_t& scalar);
[[nodiscard]] curve_point make_affine() const noexcept;
[[ nodiscard ]] curve_point make_affine() const;
curve_point neg() const noexcept;
void neg(const curve_point& a);
};
inline std::ostream& operator << (std::ostream& os, const curve_point& v) {
return os << v.string();
bool operator==(const curve_point& rhs) const noexcept {
static_assert(std::is_standard_layout_v<curve_point>);
return memcmp(this, &rhs, sizeof(*this)) == 0;
}
}
bool operator!=(const curve_point& rhs) const noexcept { return !(*this == rhs); }
};
inline const curve_point curve_point::infinity = { { 0 }, new_gfp(1), { 0 }, { 0 } };
inline std::ostream& operator<<(std::ostream& os, const curve_point& v) { return os << v.string(); }
} // namespace bn256
+78 -93
View File
@@ -1,108 +1,93 @@
#include <constants.h>
#include <gfp.h>
#include <gfp_generic.h>
#include <constants.h>
#include <iostream>
namespace bn256 {
void gfp::set_zero() noexcept {
this->fill(0);
}
gfp gfp::invert() const noexcept {
constexpr uint64_array_4_t bits = { 0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029 };
gfp gfp::invert() const noexcept {
constexpr uint64_array_4_t bits = {
0x3c208c16d87cfd45,
0x97816a916871ca8d,
0xb85045b68181585d,
0x30644e72e131a029
};
gfp sum{}, power{};
sum = constants::rn1;
power = *this;
gfp sum{}, power{};
sum = constants::rn1;
power = *this;
for (auto word = 0; word < bits.size(); word++) {
for (auto bit = 0; bit < 64; bit++) {
if (((bits[word] >> bit) & 1) == 1) {
sum = sum.mul(power);
}
power = power.mul(power);
}
}
sum = sum.mul(constants::r3);
return sum;
}
void gfp::marshal(nonstd::span<uint8_t, 32> out) const noexcept {
for (auto w = 0; w < 4; w++) {
for (auto b = 0; b < 8; b++) {
uint8_t t = ((*this)[3-w] >> (56 - 8*b));
out[8*w+b] = t;
for (auto word = 0; word < bits.size(); word++) {
for (auto bit = 0; bit < 64; bit++) {
if (((bits[word] >> bit) & 1) == 1) {
sum = sum.mul(power);
}
power = power.mul(power);
}
}
std::error_code gfp::unmarshal(nonstd::span<const uint8_t, 32> in) noexcept {
gfp& result = *this;
// Unmarshal the bytes into little endian form
for (auto w = 0; w < 4; w++) {
result[3-w] = 0;
for (auto b = 0; b < 8; b++) {
result[3-w] += uint64_t(in[8*w+b]) << (56 - 8*b);
}
sum = sum.mul(constants::r3);
return sum;
}
void gfp::marshal(nonstd::span<uint8_t, 32> out) const noexcept {
for (auto w = 0; w < 4; w++) {
for (auto b = 0; b < 8; b++) {
uint8_t t = ((*this)[3 - w] >> (56 - 8 * b));
out[8 * w + b] = t;
}
// Ensure the point respects the curve modulus
for (auto i = 3; i >= 0; i--) {
if (result[i] < constants::p2[i]) {
return {};
}
if (result[i] > constants::p2[i]) {
return unmarshal_error::COORDINATE_EXCEEDS_MODULUS;
}
}
return unmarshal_error::MALFORMED_POINT;
}
gfp gfp::mont_encode() const noexcept {
return this->mul(constants::r2);
}
gfp gfp::mont_decode() const noexcept {
constexpr gfp decode_b{1};
return this->mul(decode_b);
}
std::string gfp::string() const noexcept {
std::string result;
result.resize(64);
std::for_each(rbegin(), rend(), [buf = result.data()](uint64_t v) mutable{
const char hex_table[]= "0123456789abcdef";
unsigned char* p = reinterpret_cast<unsigned char*>(&v) + 8;
for (int i = 0; i < sizeof(uint64_t); ++i) {
unsigned x = *(--p);
*buf++ = hex_table[(x >> 4)];
*buf++ = hex_table[x & 0x0F];
}
});
return result;
}
gfp new_gfp(int64_t x) noexcept {
gfp out{};
if (x >= 0) {
out = {uint64_t(x)};
} else {
out = {uint64_t(-x)};
out = out.neg();
}
return out.mont_encode();
}
std::ostream& operator << (std::ostream& os, const gfp& v) {
os << v.string();
return os;
}
}
std::error_code gfp::unmarshal(nonstd::span<const uint8_t, 32> in) noexcept {
gfp& result = *this;
// Unmarshal the bytes into little endian form
for (auto w = 0; w < 4; w++) {
result[3 - w] = 0;
for (auto b = 0; b < 8; b++) { result[3 - w] += uint64_t(in[8 * w + b]) << (56 - 8 * b); }
}
// Ensure the point respects the curve modulus
for (auto i = 3; i >= 0; i--) {
if (result[i] < constants::p2[i]) {
return {};
}
if (result[i] > constants::p2[i]) {
return unmarshal_error::COORDINATE_EXCEEDS_MODULUS;
}
}
return unmarshal_error::MALFORMED_POINT;
}
gfp gfp::mont_encode() const noexcept { return mul(constants::r2); }
gfp gfp::mont_decode() const noexcept { return mul(gfp{ 1 }); }
std::string gfp::string() const {
std::string result;
result.resize(64);
std::for_each(rbegin(), rend(), [buf = result.data()](uint64_t v) mutable {
const char hex_table[] = "0123456789abcdef";
unsigned char* p = reinterpret_cast<unsigned char*>(&v) + 8;
for (int i = 0; i < sizeof(uint64_t); ++i) {
unsigned x = *(--p);
*buf++ = hex_table[(x >> 4)];
*buf++ = hex_table[x & 0x0F];
}
});
return result;
}
gfp new_gfp(int64_t x) noexcept {
gfp out{};
if (x >= 0) {
out = { uint64_t(x) };
} else {
out = { uint64_t(-x) };
out = out.neg();
}
return out.mont_encode();
}
std::ostream& operator<<(std::ostream& os, const gfp& v) {
os << v.string();
return os;
}
} // namespace bn256
+74 -85
View File
@@ -1,98 +1,87 @@
#pragma once
#include <cstdint>
#include "gfp_generic.h"
#include <array>
#include <string>
#include <cstdint>
#include <iosfwd>
#include <nonstd/span.hpp>
#include <string>
#include <system_error>
#include "gfp_generic.h"
namespace bn256 {
typedef std::array<uint64_t, 4> uint64_array_4_t;
typedef std::array<uint8_t, sizeof(uint64_array_4_t)> uint8_array_32_t;
typedef std::array<uint64_t, 4> uint64_array_4_t;
typedef std::array<uint8_t, sizeof(uint64_array_4_t)> uint8_array_32_t;
enum class unmarshal_error {
COORDINATE_EXCEEDS_MODULUS = 1,
COORDINATE_EQUALS_MODULUS,
MALFORMED_POINT
};
enum class unmarshal_error { COORDINATE_EXCEEDS_MODULUS = 1, COORDINATE_EQUALS_MODULUS, MALFORMED_POINT };
namespace {
struct unmarshal_error_category : std::error_category
{
const char* name() const noexcept override { return "unmarshall"; }
std::string message(int ev) const override {
switch (static_cast<unmarshal_error>(ev))
{
case unmarshal_error::COORDINATE_EXCEEDS_MODULUS:
return "coordinate exceeds modulus";
case unmarshal_error::COORDINATE_EQUALS_MODULUS:
return "coordinate equal modulus";
case unmarshal_error::MALFORMED_POINT:
return "malformed point";
default:
return "(unrecognized error)";
}
}
};
}
namespace {
struct unmarshal_error_category : std::error_category {
const char* name() const noexcept override { return "unmarshall"; }
std::string message(int ev) const override {
switch (static_cast<unmarshal_error>(ev)) {
case unmarshal_error::COORDINATE_EXCEEDS_MODULUS: return "coordinate exceeds modulus";
case unmarshal_error::COORDINATE_EQUALS_MODULUS: return "coordinate equal modulus";
case unmarshal_error::MALFORMED_POINT: return "malformed point";
default: return "(unrecognized error)";
}
}
};
} // namespace
inline std::error_code make_error_code(unmarshal_error e) noexcept
{
static const unmarshal_error_category category;
return {static_cast<int>(e), category};
}
struct gfp : std::array<uint64_t, 4> {
void set_zero() noexcept;
gfp invert() const noexcept;
gfp neg() const noexcept {
gfp r;
gfp_neg(r, *this);
return r;
}
gfp add(const gfp& other) const noexcept {
gfp r;
gfp_add(r, *this, other);
return r;
}
gfp sub(const gfp& other) const noexcept {
gfp r;
gfp_sub(r, *this, other);
return r;
}
gfp mul(const gfp& other) const noexcept {
gfp r;
gfp_mul(r, *this, other);
return r;
}
void marshal(nonstd::span<uint8_t, 32> out) const noexcept;
[[nodiscard]] std::error_code unmarshal(nonstd::span<const uint8_t, 32> input) noexcept;
gfp mont_encode() const noexcept;
gfp mont_decode() const noexcept;
std::string string() const noexcept;
};
gfp new_gfp(int64_t x) noexcept;
std::ostream& operator << (std::ostream& os, const gfp& v);
inline std::error_code make_error_code(unmarshal_error e) noexcept {
static const unmarshal_error_category category;
return { static_cast<int>(e), category };
}
namespace std
{
template <> struct is_error_code_enum<bn256::unmarshal_error> : true_type
{
};
}
struct gfp : std::array<uint64_t, 4> {
static constexpr gfp zero() noexcept { return {}; }
static constexpr gfp one() noexcept {
return { 0xd35d438dc58f0d9d, 0x0a78eb28f5c70b3d, 0x666ea36f7879462c, 0x0e0a77c19a07df2f };
}
gfp invert() const noexcept;
gfp neg() const noexcept {
gfp r;
gfp_neg(r, *this);
return r;
}
gfp add(const gfp& other) const noexcept {
gfp r;
gfp_add(r, *this, other);
return r;
}
gfp sub(const gfp& other) const noexcept {
gfp r;
gfp_sub(r, *this, other);
return r;
}
gfp mul(const gfp& other) const noexcept {
gfp r;
gfp_mul(r, *this, other);
return r;
}
void marshal(nonstd::span<uint8_t, 32> out) const noexcept;
[[nodiscard]] std::error_code unmarshal(nonstd::span<const uint8_t, 32> input) noexcept;
gfp mont_encode() const noexcept;
gfp mont_decode() const noexcept;
std::string string() const;
};
gfp new_gfp(int64_t x) noexcept;
std::ostream& operator<<(std::ostream& os, const gfp& v);
} // namespace bn256
namespace std {
template <>
struct is_error_code_enum<bn256::unmarshal_error> : true_type {};
} // namespace std
+122 -166
View File
@@ -1,173 +1,129 @@
#include <gfp12.h>
#include <constants.h>
#include <bitlen.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <constants.h>
#include <gfp12.h>
#include <sstream>
namespace bn256 {
const gfp12& gfp12::set_zero() {
x_.set_zero();
y_.set_zero();
return *this;
}
const gfp12& gfp12::set_one() {
x_.set_zero();
y_.set_one();
return *this;
}
bool gfp12::is_zero() const {
return x_.is_zero() &&
y_.is_zero();
}
bool gfp12::is_one() const {
return x_.is_zero() &&
y_.is_one();
}
const gfp12& gfp12::conjugate(const gfp12& a) {
x_.neg(a.x_);
y_ = a.y_;
return *this;
}
const gfp12& gfp12::neg(const gfp12& a) {
x_.neg(a.x_);
y_.neg(a.y_);
return *this;
}
// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
const gfp12& gfp12::frobenius(const gfp12& a) {
x_.frobenius(a.x_);
y_.frobenius(a.y_);
x_.mul_scalar(x_, constants::xi_to_p_minus_1_over_6);
return *this;
}
// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
const gfp12& gfp12::frobenius_p2(const gfp12& a) {
x_.frobenius_p2(a.x_);
x_.mul_gfp(x_, constants::xi_to_p_squared_minus_1_over_6);
y_.frobenius_p2(a.y_);
return *this;
}
const gfp12& gfp12::frobenius_p4(const gfp12& a) {
x_.frobenius_p4(a.x_);
x_.mul_gfp(x_, constants::xi_to_p_squared_minus_1_over_3);
y_.frobenius_p4(a.y_);
return *this;
}
const gfp12& gfp12::add(const gfp12& a, const gfp12& b) {
x_.add(a.x_, b.x_);
y_.add(a.y_, b.y_);
return *this;
}
const gfp12& gfp12::sub(const gfp12& a, const gfp12& b) {
x_.sub(a.x_, b.x_);
y_.sub(a.y_, b.y_);
return *this;
}
const gfp12& gfp12::mul(const gfp12& a, const gfp12& b) {
gfp6 tx{}, t{}, ty{};
tx.mul(a.x_, b.y_);
t.mul(b.x_, a.y_);
tx.add(tx, t);
ty.mul(a.y_, b.y_);
t.mul(a.x_, b.x_);
t.mul_tau(t);
x_ = tx;
y_.add(ty, t);
return *this;
}
const gfp12& gfp12::mul_scalar(const gfp12& a, const gfp6& b) {
x_.mul(x_, b);
y_.mul(y_, b);
return *this;
}
const gfp12& gfp12::exp(const gfp12& a, const int512_t& power) {
gfp12 sum{}, t{};
sum.set_one();
for (int i = bitlen(power); i >= 0; i--) {
t.square(sum);
if (bit_test(power, i) != 0) {
sum.mul(t, a);
} else {
sum = t;
}
}
*this = sum;
return *this;
}
const gfp12& gfp12::square(const gfp12& a) {
// Complex squaring algorithm
gfp6 v0{}, t{}, ty{};
v0.mul(a.x_, a.y_);
t.mul_tau(a.x_);
t.add(a.y_, t);
ty.add(a.x_, a.y_);
ty.mul(ty, t);
ty.sub(ty, v0);
t.mul_tau(v0);
ty.sub(ty, t);
x_.add(v0, v0);
y_ = ty;
return *this;
}
const gfp12& gfp12::invert(const gfp12& a) {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
gfp6 t1{}, t2{};
t1.square(a.x_);
t2.square(a.y_);
t1.mul_tau(t1);
t1.sub(t2, t1);
t2.invert(t1);
x_.neg(a.x_);
y_ = a.y_;
mul_scalar(*this, t2);
return *this;
}
bool gfp12::operator==(const gfp12& rhs) const {
return x_ == rhs.x_ &&
y_ == rhs.y_;
}
bool gfp12::operator!=(const gfp12& rhs) const {
return !(rhs == *this);
}
std::string gfp12::string() {
std::stringstream ss;
ss << "(" << x_.string() << ", " << y_.string() << ")";
return ss.str();
}
std::ostream& operator << (std::ostream& os, const gfp12& v) {
return os << "(" << v.x_ << ", " << v.y_ << ")";
}
gfp12 gfp12::conjugate() const noexcept {
const gfp12& a = *this;
return { a.x_.neg(), a.y_ };
}
gfp12 gfp12::neg() const noexcept {
const gfp12& a = *this;
return { a.x_.neg(), a.y_.neg() };
}
// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
gfp12 gfp12::frobenius() const noexcept {
const gfp12& a = *this;
gfp12 e;
e.x_ = a.x_.frobenius();
e.y_ = a.y_.frobenius();
e.x_ = e.x_.mul_scalar(constants::xi_to_p_minus_1_over_6);
return e;
}
// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
gfp12 gfp12::frobenius_p2() const noexcept {
const gfp12& a = *this;
gfp12 e;
e.x_ = a.x_.frobenius_p2();
e.x_ = e.x_.mul_gfp(constants::xi_to_p_squared_minus_1_over_6);
e.y_ = a.y_.frobenius_p2();
return e;
}
gfp12 gfp12::frobenius_p4() const noexcept {
const gfp12& a = *this;
gfp12 e;
e.x_ = a.x_.frobenius_p4();
e.x_ = e.x_.mul_gfp(constants::xi_to_p_squared_minus_1_over_3);
e.y_ = a.y_.frobenius_p4();
return e;
}
gfp12 gfp12::add(const gfp12& b) const noexcept {
const gfp12& a = *this;
return { a.x_.add(b.x_), a.y_.add(b.y_) };
}
gfp12 gfp12::sub(const gfp12& b) const noexcept {
const gfp12& a = *this;
return { a.x_.sub(b.x_), a.y_.sub(b.y_) };
}
gfp12 gfp12::mul(const gfp12& b) const noexcept {
const gfp12& a = *this;
gfp6 tx = a.x_.mul(b.y_);
gfp6 t = b.x_.mul(a.y_);
tx = tx.add(t);
gfp6 ty = a.y_.mul(b.y_);
t = a.x_.mul(b.x_).mul_tau();
return { tx, ty.add(t) };
}
gfp12 gfp12::mul_scalar(const gfp6& b) const noexcept {
const gfp12& a = *this;
return { a.x_.mul(b), a.y_.mul(b) }; // need review ???
}
gfp12 gfp12::exp(const int512_t& power) const noexcept {
const gfp12& a = *this;
gfp12 sum = one(), t;
for (int i = bitlen(power); i >= 0; i--) {
t = sum.square();
if (bit_test(power, i) != 0) {
sum = t.mul(a);
} else {
sum = t;
}
}
return sum;
}
gfp12 gfp12::square() const noexcept {
const gfp12& a = *this;
// Complex squaring algorithm
gfp6 v0 = a.x_.mul(a.y_);
gfp6 t = a.x_.mul_tau();
t = a.y_.add(t);
gfp6 ty = a.x_.add(a.y_);
ty = ty.mul(t).sub(v0);
t = v0.mul_tau();
ty = ty.sub(t);
return { v0.add(v0), ty };
}
gfp12 gfp12::invert() const noexcept {
const gfp12& a = *this;
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
gfp6 t1 = a.x_.square();
gfp6 t2 = a.y_.square();
t1 = t1.mul_tau();
t1 = t2.sub(t1);
t2 = t1.invert();
gfp12 e;
e.x_ = a.x_.neg();
e.y_ = a.y_;
e = e.mul_scalar(t2);
return e;
}
std::string gfp12::string() const { return "(" + x_.string() + "," + y_.string() + ")"; }
std::ostream& operator<<(std::ostream& os, const gfp12& v) { return os << "(" << v.x_ << "," << v.y_ << ")"; }
} // namespace bn256
+34 -31
View File
@@ -1,59 +1,62 @@
#pragma once
#include <gfp6.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <gfp6.h>
using boost::multiprecision::int512_t;
namespace bn256 {
// gfp12 implements the field of size p¹² as a quadratic extension of gfp6
// where ω²=τ.
struct gfp12 {
// value is xω + y
gfp6 x_;
gfp6 y_;
// gfp12 implements the field of size p¹² as a quadratic extension of gfp6
// where ω²=τ.
struct gfp12 {
// value is xω + y
gfp6 x_;
gfp6 y_;
const gfp12& set_zero();
static constexpr gfp12 zero() noexcept { return {}; }
static constexpr gfp12 one() noexcept { return {{}, gfp6::one()}; }
const gfp12& set_one();
void set_zero() noexcept { *this = zero(); }
void set_one() noexcept { *this = one(); }
[[nodiscard]] bool is_zero() const;
bool is_zero() const noexcept { return *this == zero(); }
bool is_one() const noexcept { return *this == one(); }
[[nodiscard]] bool is_one() const;
gfp12 conjugate() const noexcept;
const gfp12& conjugate(const gfp12& a);
gfp12 neg() const noexcept;
const gfp12& neg(const gfp12& a);
gfp12 frobenius() const noexcept;
const gfp12& frobenius(const gfp12& a);
gfp12 frobenius_p2() const noexcept;
const gfp12& frobenius_p2(const gfp12& a);
gfp12 frobenius_p4() const noexcept;
const gfp12& frobenius_p4(const gfp12& a);
gfp12 add(const gfp12& b) const noexcept;
const gfp12& add(const gfp12& a, const gfp12& b);
gfp12 sub(const gfp12& b) const noexcept;
const gfp12& sub(const gfp12& a, const gfp12& b);
gfp12 mul(const gfp12& b) const noexcept;
const gfp12& mul(const gfp12& a, const gfp12& b);
gfp12 mul_scalar(const gfp6& b) const noexcept;
const gfp12& mul_scalar(const gfp12& a, const gfp6& b);
gfp12 exp(const int512_t& power) const noexcept;
const gfp12& exp(const gfp12& a, const int512_t& power);
gfp12 square() const noexcept;
const gfp12& square(const gfp12& a);
gfp12 invert() const noexcept;
const gfp12& invert(const gfp12& a);
bool operator==(const gfp12& rhs) const noexcept {
static_assert(std::is_standard_layout_v<gfp12>);
return memcmp(this, &rhs, sizeof(*this)) == 0;
}
bool operator==(const gfp12& rhs) const;
bool operator!=(const gfp12& rhs) const noexcept { return !(*this == rhs); }
bool operator!=(const gfp12& rhs) const;
std::string string() const;
};
std::string string();
std::ostream& operator<<(std::ostream& os, const gfp12& v);
};
std::ostream& operator << (std::ostream& os, const gfp12& v);
}
} // namespace bn256
+26 -72
View File
@@ -3,84 +3,52 @@
namespace bn256 {
gfp2 gfp2::gfp2_decode(const gfp2& in) {
gfp2 gfp2::gfp2_decode(const gfp2& in) noexcept {
return {in.x_.mont_decode(), in.y_.mont_decode()};
}
const gfp2& gfp2::set_zero() {
x_.set_zero();
y_.set_zero();
return *this;
gfp2 gfp2::conjugate() const noexcept {
return { x_.neg(), y_};
}
const gfp2& gfp2::set_one() {
x_.set_zero();
y_ = new_gfp(1);
return *this;
gfp2 gfp2::neg() const noexcept {
return { x_.neg(), y_.neg() };
}
bool gfp2::is_zero() const {
constexpr gfp zero{};
return zero == x_ && zero == y_;
gfp2 gfp2::add(const gfp2& b) const noexcept {
return {x_.add(b.x_), y_.add(b.y_)};
}
bool gfp2::is_one() const {
constexpr gfp zero{};
static const gfp one = new_gfp(1);
return zero == x_ && one == y_;
}
const gfp2& gfp2::conjugate(const gfp2& a) {
y_ = a.y_;
x_ = a.x_.neg();
return *this;
}
const gfp2& gfp2::neg(const gfp2& a) {
x_ = a.x_.neg();
y_ = a.y_.neg();
return *this;
}
const gfp2& gfp2::add(const gfp2& a, const gfp2& b) {
x_ = a.x_.add(b.x_);
y_ = a.y_.add(b.y_);
return *this;
}
const gfp2& gfp2::sub(const gfp2& a, const gfp2& b) {
x_ = a.x_.sub(b.x_);
y_ = a.y_.sub(b.y_);
return *this;
gfp2 gfp2::sub(const gfp2& b) const noexcept {
return { x_.sub(b.x_), y_.sub(b.y_)};
}
// See "Multiplication and Squaring in Pairing-Friendly Fields",
// http://eprint.iacr.org/2006/471.pdf
const gfp2& gfp2::mul(const gfp2& a, const gfp2& b) {
gfp tx{}, t{}, ty{};
gfp2 gfp2::mul(const gfp2& b) const noexcept {
const gfp2& a = *this;
gfp tx, t;
tx = a.x_.mul(b.y_);
t = b.x_.mul(a.y_);
tx = tx.add(t);
gfp ty;
ty = a.y_.mul(b.y_);
t = a.x_.mul(b.x_);
ty = ty.sub(t);
x_ = tx;
y_ = ty;
return *this;
return { tx, ty};
}
const gfp2& gfp2::mul_scalar(const gfp2& a, const gfp& b) {
x_ = a.x_.mul(b);
y_ = a.y_.mul(b);
return *this;
gfp2 gfp2::mul_scalar(const gfp& b) const noexcept {
return { x_.mul(b), y_.mul(b)};
}
// MulXi sets e=ξa where ξ=i+9 and then returns e.
const gfp2& gfp2::mul_xi(const gfp2& a) {
gfp2 gfp2::mul_xi() const noexcept {
const gfp2& a = *this;
gfp tx;
tx = a.x_.add(a.x_);
tx = tx.add(tx);
@@ -97,15 +65,13 @@ namespace bn256 {
ty = ty.sub(a.x_);
x_ = tx;
y_ = ty;
return *this;
return { tx, ty };
}
const gfp2& gfp2::square(const gfp2& a) {
gfp2 gfp2::square() const noexcept {
// Complex squaring algorithm:
// (xi+y)² = (x+y)(y-x) + 2*i*x*y
const gfp2& a = *this;
gfp tx{}, ty{};
tx = a.y_.sub(a.x_);
ty = a.x_.add(a.y_);
@@ -114,15 +80,13 @@ namespace bn256 {
tx = a.x_.mul(a.y_);
tx = tx.add(tx);
x_ = tx;
y_ = ty;
return *this;
return { tx, ty };
}
const gfp2& gfp2::invert(const gfp2& a) {
gfp2 gfp2::invert() const noexcept {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
const gfp2& a = *this;
gfp t1{}, t2{};
t1 = a.x_.mul(a.x_);
@@ -133,20 +97,10 @@ namespace bn256 {
t1 = a.x_.neg();
x_ = t1.mul(inv);
y_ = a.y_.mul(inv);
return *this;
return {t1.mul(inv), a.y_.mul(inv)};
}
bool gfp2::operator==(const gfp2& rhs) const {
return x_ == rhs.x_ &&
y_ == rhs.y_;
}
bool gfp2::operator!=(const gfp2& rhs) const {
return !(rhs == *this);
}
std::string gfp2::string() const {
std::stringstream ss;
+30 -27
View File
@@ -4,48 +4,51 @@
namespace bn256 {
// gfp2 implements a field of size p² as a quadratic extension of the base field
// where i²=-1.
struct gfp2 {
gfp x_{};
gfp y_{};
// gfp2 implements a field of size p² as a quadratic extension of the base field
// where i²=-1.
struct gfp2 {
gfp x_;
gfp y_;
static gfp2 gfp2_decode(const gfp2& in);
static gfp2 gfp2_decode(const gfp2& in) noexcept;
const gfp2& set_zero();
static constexpr gfp2 zero() noexcept { return {}; }
static constexpr gfp2 one() noexcept { return {{}, gfp::one()}; }
const gfp2& set_one();
void set_zero() noexcept { *this = zero(); }
void set_one() noexcept { *this = one(); }
[[nodiscard]] bool is_zero() const;
bool is_zero() const noexcept { return *this == zero(); }
bool is_one() const noexcept { return *this == one(); }
[[nodiscard]] bool is_one() const;
gfp2 conjugate() const noexcept;
const gfp2& conjugate(const gfp2& a);
gfp2 neg() const noexcept;
const gfp2& neg(const gfp2& a);
gfp2 add(const gfp2& b) const noexcept;
const gfp2& add(const gfp2& a, const gfp2& b);
gfp2 sub(const gfp2& b) const noexcept;
const gfp2& sub(const gfp2& a, const gfp2& b);
gfp2 mul(const gfp2& b) const noexcept;
const gfp2& mul(const gfp2& a, const gfp2& b);
gfp2 mul_scalar(const gfp& b) const noexcept;
const gfp2& mul_scalar(const gfp2& a, const gfp& b);
gfp2 mul_xi() const noexcept;
const gfp2& mul_xi(const gfp2& a);
gfp2 square() const noexcept;
const gfp2& square(const gfp2& a);
gfp2 invert() const noexcept;
const gfp2& invert(const gfp2& a);
bool operator==(const gfp2& rhs) const noexcept {
static_assert(std::is_standard_layout_v<gfp2>);
return memcmp(this, &rhs, sizeof(*this)) == 0;
}
bool operator==(const gfp2& rhs) const;
bool operator!=(const gfp2& rhs) const noexcept { return !(*this == rhs); }
bool operator!=(const gfp2& rhs) const;
std::string string() const;
};
std::string string() const;
std::ostream& operator<<(std::ostream& os, const gfp2& v);
};
std::ostream& operator << (std::ostream& os, const gfp2& v);
}
} // namespace bn256
+191 -244
View File
@@ -1,250 +1,197 @@
#include <gfp6.h>
#include <constants.h>
#include <gfp6.h>
#include <sstream>
namespace bn256 {
const gfp6& gfp6::set_zero() {
x_.set_zero();
y_.set_zero();
z_.set_zero();
return *this;
}
const gfp6& gfp6::set_one() {
x_.set_zero();
y_.set_zero();
z_.set_one();
return *this;
}
bool gfp6::is_zero() const {
return x_.is_zero() &&
y_.is_zero() &&
z_.is_zero();
}
bool gfp6::is_one() const {
return x_.is_zero() &&
y_.is_zero() &&
z_.is_one();
}
const gfp6& gfp6::neg(const gfp6& a) {
x_.neg(a.x_);
y_.neg(a.y_);
z_.neg(a.z_);
return *this;
}
const gfp6& gfp6::frobenius(const gfp6& a) {
x_.conjugate(a.x_);
y_.conjugate(a.y_);
z_.conjugate(a.z_);
x_.mul(x_, constants::xi_to_2p_minus_2_over_3);
y_.mul(y_, constants::xi_to_p_minus_1_over_3);
return *this;
}
// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
const gfp6& gfp6::frobenius_p2(const gfp6& a) {
// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
x_.mul_scalar(a.x_, constants::xi_to_2p_squared_minus_2_over_3);
// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
y_.mul_scalar(a.y_, constants::xi_to_p_squared_minus_1_over_3);
z_ = a.z_;
return *this;
}
const gfp6& gfp6::frobenius_p4(const gfp6& a) {
x_.mul_scalar(a.x_, constants::xi_to_p_squared_minus_1_over_3);
y_.mul_scalar(a.y_, constants::xi_to_2p_squared_minus_2_over_3);
z_ = a.z_;
return *this;
}
const gfp6& gfp6::add(const gfp6& a, const gfp6& b) {
x_.add(a.x_, b.x_);
y_.add(a.y_, b.y_);
z_.add(a.z_, b.z_);
return *this;
}
const gfp6& gfp6::sub(const gfp6& a, const gfp6& b) {
x_.sub(a.x_, b.x_);
y_.sub(a.y_, b.y_);
z_.sub(a.z_, b.z_);
return *this;
}
const gfp6& gfp6::mul(const gfp6& a, const gfp6& b) {
// "Multiplication and Squaring on Pairing-Friendly Fields"
// Section 4, Karatsuba method.
// http://eprint.iacr.org/2006/471.pdf
gfp2 v0{}, v1{}, v2{}, t0{}, t1{}, tz{}, ty{}, tx{};
v0.mul(a.z_, b.z_);
v1.mul(a.y_, b.y_);
v2.mul(a.x_, b.x_);
t0.add(a.x_, a.y_);
t1.add(b.x_, b.y_);
tz.mul(t0, t1);
tz.sub(tz, v1);
tz.sub(tz, v2);
tz.mul_xi(tz);
tz.add(tz, v0);
t0.add(a.y_, a.z_);
t1.add(b.y_, b.z_);
ty.mul(t0, t1);
t0.mul_xi(v2);
ty.sub(ty, v0);
ty.sub(ty, v1);
ty.add(ty, t0);
t0.add(a.x_, a.z_);
t1.add(b.x_, b.z_);
tx.mul(t0, t1);
tx.sub(tx, v0);
tx.add(tx, v1);
tx.sub(tx, v2);
x_ = tx;
y_ = ty;
z_ = tz;
return *this;
}
const gfp6& gfp6::mul_scalar(const gfp6& a, const gfp2& b) {
x_.mul(a.x_, b);
y_.mul(a.y_, b);
z_.mul(a.z_, b);
return *this;
}
const gfp6& gfp6::mul_gfp(const gfp6& a, const gfp& b) {
x_.mul_scalar(a.x_, b);
y_.mul_scalar(a.y_, b);
z_.mul_scalar(a.z_, b);
return *this;
}
const gfp6& gfp6::mul_tau(const gfp6& a) {
gfp2 tz{}, ty{};
tz.mul_xi(a.x_);
ty = a.y_;
y_ = a.z_;
x_ = ty;
z_ = tz;
return *this;
}
const gfp6& gfp6::square(const gfp6& a) {
gfp2 v0{}, v1{}, v2{}, c0{}, c1{}, xi_v2{}, c2{};
v0.square(a.z_);
v1.square(a.y_);
v2.square(a.x_);
c0.add(a.x_, a.y_);
c0.square(c0);
c0.sub(c0, v1);
c0.sub(c0, v2);
c0.mul_xi(c0);
c0.add(c0, v0);
c1.add(a.y_, a.z_);
c1.square(c1);
c1.sub(c1, v0);
c1.sub(c1, v1);
xi_v2.mul_xi(v2);
c1.add(c1, xi_v2);
c2.add(a.x_, a.z_);
c2.square(c2);
c2.sub(c2, v0);
c2.add(c2, v1);
c2.sub(c2, v2);
x_ = c2;
y_ = c1;
z_ = c0;
return *this;
}
const gfp6& gfp6::invert(const gfp6& a) {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
// Here we can give a short explanation of how it works: let j be a cubic root of
// unity in GF(p²) so that 1+j+j²=0.
// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = (xτ² + yτ + z)(Cτ²+Bτ+A)
// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
//
// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
//
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
gfp2 t1{}, a2{}, b{}, c{}, f{};
t1.mul(a.x_, a.y_);
t1.mul_xi(t1);
a2.square(a.z_);
a2.sub(a2, t1);
b.square(a.x_);
b.mul_xi(b);
t1.mul(a.y_, a.z_);
b.sub(b, t1);
c.square(a.y_);
t1.mul(a.x_, a.z_);
c.sub(c, t1);
f.mul(c, a.y_);
f.mul_xi(f);
t1.mul(a2, a.z_);
f.add(f, t1);
t1.mul(b, a.x_);
t1.mul_xi(t1);
f.add(f, t1);
f.invert(f);
x_.mul(c, f);
y_.mul(b, f);
z_.mul(a2, f);
return *this;
}
bool gfp6::operator==(const gfp6& rhs) const {
return x_ == rhs.x_ &&
y_ == rhs.y_ &&
z_ == rhs.z_;
}
bool gfp6::operator!=(const gfp6& rhs) const {
return !(rhs == *this);
}
std::string gfp6::string() {
std::stringstream ss;
ss << "(" << x_.string() << ", " << y_.string() << ", " << z_.string() << ")";
return ss.str();
}
std::ostream& operator << (std::ostream& os, const gfp6& v) {
return os << "(" << v.x_ << ", " << v.y_ << ", " << v.z_ << ")";
}
gfp6 gfp6::neg() const noexcept {
const gfp6& a = *this;
return { a.x_.neg(), a.y_.neg(), a.z_.neg() };
}
gfp6 gfp6::frobenius() const noexcept {
const gfp6& a = *this;
gfp6 e = { a.x_.conjugate(), a.y_.conjugate(), a.z_.conjugate() };
e.x_ = e.x_.mul(constants::xi_to_2p_minus_2_over_3);
e.y_ = e.y_.mul(constants::xi_to_p_minus_1_over_3);
return e;
}
// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
gfp6 gfp6::frobenius_p2() const noexcept {
const gfp6& a = *this;
gfp6 e;
// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
e.x_ = a.x_.mul_scalar(constants::xi_to_2p_squared_minus_2_over_3);
// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
e.y_ = a.y_.mul_scalar(constants::xi_to_p_squared_minus_1_over_3);
e.z_ = a.z_;
return e;
}
gfp6 gfp6::frobenius_p4() const noexcept {
const gfp6& a = *this;
gfp6 e;
e.x_ = a.x_.mul_scalar(constants::xi_to_p_squared_minus_1_over_3);
e.y_ = a.y_.mul_scalar(constants::xi_to_2p_squared_minus_2_over_3);
e.z_ = a.z_;
return e;
}
gfp6 gfp6::add(const gfp6& b) const noexcept {
const gfp6& a = *this;
gfp6 e;
e.x_ = a.x_.add(b.x_);
e.y_ = a.y_.add(b.y_);
e.z_ = a.z_.add(b.z_);
return e;
}
gfp6 gfp6::sub(const gfp6& b) const noexcept {
const gfp6& a = *this;
gfp6 e;
e.x_ = a.x_.sub(b.x_);
e.y_ = a.y_.sub(b.y_);
e.z_ = a.z_.sub(b.z_);
return e;
}
gfp6 gfp6::mul(const gfp6& b) const noexcept {
const gfp6& a = *this;
// "Multiplication and Squaring on Pairing-Friendly Fields"
// Section 4, Karatsuba method.
// http://eprint.iacr.org/2006/471.pdf
gfp2 v0 = a.z_.mul(b.z_);
gfp2 v1 = a.y_.mul(b.y_);
gfp2 v2 = a.x_.mul(b.x_);
gfp2 t0 = a.x_.add(a.y_);
gfp2 t1 = b.x_.add(b.y_);
gfp2 tz = t0.mul(t1);
tz = tz.sub(v1).sub(v2).mul_xi().add(v0);
t0 = a.y_.add(a.z_);
t1 = b.y_.add(b.z_);
gfp2 ty = t0.mul(t1);
t0 = v2.mul_xi();
ty = ty.sub(v0).sub(v1).add(t0);
t0 = a.x_.add(a.z_);
t1 = b.x_.add(b.z_);
gfp2 tx = t0.mul(t1);
tx = tx.sub(v0).add(v1).sub(v2);
return { tx, ty, tz };
}
gfp6 gfp6::mul_scalar(const gfp2& b) const noexcept {
const gfp6& a = *this;
gfp6 e;
e.x_ = a.x_.mul(b);
e.y_ = a.y_.mul(b);
e.z_ = a.z_.mul(b);
return e;
}
gfp6 gfp6::mul_gfp(const gfp& b) const noexcept {
const gfp6& a = *this;
gfp6 e;
e.x_ = a.x_.mul_scalar(b);
e.y_ = a.y_.mul_scalar(b);
e.z_ = a.z_.mul_scalar(b);
return e;
}
gfp6 gfp6::mul_tau() const noexcept {
const gfp6& a = *this;
gfp6 e;
gfp2 tz = a.x_.mul_xi();
gfp2 ty = a.y_;
e.y_ = a.z_;
e.x_ = ty;
e.z_ = tz;
return e;
}
gfp6 gfp6::square() const noexcept {
const gfp6& a = *this;
gfp2 v0 = a.z_.square();
gfp2 v1 = a.y_.square();
gfp2 v2 = a.x_.square();
gfp2 c0 = a.x_.add(a.y_);
c0 = c0.square().sub(v1).sub(v2).mul_xi().add(v0);
gfp2 c1 = a.y_.add(a.z_);
c1 = c1.square().sub(v0).sub(v1);
gfp2 xi_v2 = v2.mul_xi();
c1 = c1.add(xi_v2);
gfp2 c2 = a.x_.add(a.z_);
c2 = c2.square().sub(v0).add(v1).sub(v2);
return { c2, c1, c0 };
}
gfp6 gfp6::invert() const noexcept {
const gfp6& a = *this;
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
// Here we can give a short explanation of how it works: let j be a cubic root of
// unity in GF(p²) so that 1+j+j²=0.
// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = (xτ² + yτ + z)(Cτ²+Bτ+A)
// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
//
// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
//
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
gfp2 t1 = a.x_.mul(a.y_);
t1 = t1.mul_xi();
gfp2 A = a.z_.square();
A = A.sub(t1);
gfp2 B = a.x_.square();
B = B.mul_xi();
t1 = a.y_.mul(a.z_);
B = B.sub(t1);
gfp2 C = a.y_.square();
t1 = a.x_.mul(a.z_);
C = C.sub(t1);
gfp2 F = C.mul(a.y_);
F = F.mul_xi();
t1 = A.mul(a.z_);
F = F.add(t1);
t1 = B.mul(a.x_);
t1 = t1.mul_xi();
F = F.add(t1);
F = F.invert();
gfp6 e;
e.x_ = C.mul(F);
e.y_ = B.mul(F);
e.z_ = A.mul(F);
return e;
}
std::string gfp6::string() const {
return "(" + x_.string() + ", " + y_.string() + ", " + z_.string() + ")";
}
std::ostream& operator<<(std::ostream& os, const gfp6& v) {
return os << "(" << v.x_ << ", " << v.y_ << ", " << v.z_ << ")";
}
} // namespace bn256
+32 -31
View File
@@ -4,53 +4,54 @@
namespace bn256 {
// gfp6 implements the field of size p⁶ as a cubic extension of gfp2 where τ³=ξ
// and ξ=i+9.
struct gfp6 {
// value is xτ² + yτ + z
gfp2 x_;
gfp2 y_;
gfp2 z_;
// gfp6 implements the field of size p⁶ as a cubic extension of gfp2 where τ³=ξ
// and ξ=i+9.
struct gfp6 {
// value is xτ² + yτ + z
gfp2 x_;
gfp2 y_;
gfp2 z_;
const gfp6& set_zero();
static constexpr gfp6 zero() noexcept { return {}; }
static constexpr gfp6 one() noexcept { return { {}, {}, gfp2::one()}; }
const gfp6& set_one();
[[nodiscard]] bool is_zero() const noexcept { return *this == zero(); }
[[nodiscard]] bool is_one() const noexcept { return *this == one(); }
[[nodiscard]] bool is_zero() const;
gfp6 neg() const noexcept;
[[nodiscard]] bool is_one() const;
gfp6 frobenius() const noexcept;
const gfp6& neg(const gfp6& a);
gfp6 frobenius_p2() const noexcept;
const gfp6& frobenius(const gfp6& a);
gfp6 frobenius_p4() const noexcept;
const gfp6& frobenius_p2(const gfp6& a);
gfp6 add(const gfp6& b) const noexcept;
const gfp6& frobenius_p4(const gfp6& a);
gfp6 sub(const gfp6& b) const noexcept;
const gfp6& add(const gfp6& a, const gfp6& b);
gfp6 mul(const gfp6& b) const noexcept;
const gfp6& sub(const gfp6& a, const gfp6& b);
gfp6 mul_scalar(const gfp2& b) const noexcept;
const gfp6& mul(const gfp6& a, const gfp6& b);
gfp6 mul_gfp(const gfp& b) const noexcept;
const gfp6& mul_scalar(const gfp6& a, const gfp2& b);
gfp6 mul_tau() const noexcept;
const gfp6& mul_gfp(const gfp6& a, const gfp& b);
gfp6 square() const noexcept;
const gfp6& mul_tau(const gfp6& a);
gfp6 invert() const noexcept;
const gfp6& square(const gfp6& a);
bool operator==(const gfp6& rhs) const noexcept {
static_assert(std::is_standard_layout_v<gfp6>);
return memcmp(this, &rhs, sizeof(*this)) == 0;
}
const gfp6& invert(const gfp6& a);
bool operator!=(const gfp6& rhs) const noexcept { return !(*this == rhs); }
bool operator==(const gfp6& rhs) const;
std::string string() const;
};
bool operator!=(const gfp6& rhs) const;
std::string string();
};
std::ostream& operator << (std::ostream& os, const gfp6& v);
}
std::ostream& operator<<(std::ostream& os, const gfp6& v);
} // namespace bn256
+56 -56
View File
@@ -1,73 +1,73 @@
#include <lattice.h>
#include <bitlen.h>
#include <lattice.h>
namespace bn256 {
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
// decompose takes a scalar mod order as input and finds a short,
// positive decomposition of it wrt to the lattice basis.
std::vector<int512_t> lattice::decompose(const int512_t& k) const {
auto n = inverse_.size();
std::vector<int512_t> c(n);
// decompose takes a scalar mod order as input and finds a short,
// positive decomposition of it wrt to the lattice basis.
std::vector<int512_t> lattice::decompose(const int512_t& k) const {
auto n = inverse_.size();
std::vector<int512_t> c(n);
// Calculate closest vector in lattice to <k,0,0,...> with Babai's rounding.
for (std::size_t i = 0; i < n; i++) {
c[i] = k * inverse_[i];
round(c[i], det_);
}
// Transform vectors according to c and subtract <k,0,0,...>.
std::vector<int512_t> out(n);
int512_t temp;
for (std::size_t i = 0; i < n; i++) {
out[i] = 0;
for (std::size_t j = 0; j < n; j++) {
temp = c[j] * vectors_[j][i];
out[i] += temp;
}
out[i].backend().negate();
out[i] += vectors_[0][i];
out[i] += vectors_[0][i];
}
out[0] += k;
return out;
// Calculate closest vector in lattice to <k,0,0,...> with Babai's rounding.
for (std::size_t i = 0; i < n; i++) {
c[i] = k * inverse_[i];
round(c[i], det_);
}
std::vector<uint8_t> lattice::multi(const int512_t& scalar) const {
std::vector<int512_t> decomp = decompose(scalar);
std::size_t maxlen = 0;
for (const auto& x: decomp) {
const auto len = bitlen(x);
if (len > maxlen) {
maxlen = len;
}
// Transform vectors according to c and subtract <k,0,0,...>.
std::vector<int512_t> out(n);
int512_t temp;
for (std::size_t i = 0; i < n; i++) {
out[i] = 0;
for (std::size_t j = 0; j < n; j++) {
temp = c[j] * vectors_[j][i];
out[i] += temp;
}
out[i].backend().negate();
out[i] += vectors_[0][i];
out[i] += vectors_[0][i];
}
out[0] += k;
return out;
}
std::vector<uint8_t> out(maxlen);
for (std::size_t j = 0; j < decomp.size(); ++j) {
for (std::size_t i = 0; i < maxlen; ++i) {
if (bit_test(decomp[j], i)) {
out[i] += (1 << j);
}
}
std::vector<uint8_t> lattice::multi(const int512_t& scalar) const {
std::vector<int512_t> decomp = decompose(scalar);
std::size_t maxlen = 0;
for (const auto& x : decomp) {
const auto len = bitlen(x);
if (len > maxlen) {
maxlen = len;
}
return out;
}
// round sets num to num/denom rounded to the nearest integer.
void lattice::round(int512_t& num, const int512_t& denom) {
if (denom != 0) {
const int512_t half = constants::order >> 1;
num /= denom;
int512_t rem = num % denom;
auto compare_result = rem.compare(half);
if (compare_result > 0) {
num++;
std::vector<uint8_t> out(maxlen);
for (std::size_t j = 0; j < decomp.size(); ++j) {
for (std::size_t i = 0; i < maxlen; ++i) {
if (bit_test(decomp[j], i)) {
out[i] += (1 << j);
}
}
}
return out;
}
// round sets num to num/denom rounded to the nearest integer.
void lattice::round(int512_t& num, const int512_t& denom) {
if (denom != 0) {
const int512_t half = constants::order >> 1;
num /= denom;
int512_t rem = num % denom;
auto compare_result = rem.compare(half);
if (compare_result > 0) {
num++;
}
}
}
} // namespace bn256
+26 -43
View File
@@ -4,21 +4,21 @@
namespace bn256 {
using namespace boost::multiprecision;
using namespace boost::multiprecision;
struct lattice {
std::vector<std::vector<int512_t>> vectors_;
std::vector<int512_t> inverse_;
const int512_t det_;
struct lattice {
std::vector<std::vector<int512_t>> vectors_;
std::vector<int512_t> inverse_;
const int512_t det_;
[[nodiscard]] std::vector<int512_t> decompose(const int512_t& k) const;
[[nodiscard]] std::vector<int512_t> decompose(const int512_t& k) const;
[[nodiscard]] std::vector<uint8_t> multi(const int512_t& scalar) const;
[[nodiscard]] std::vector<uint8_t> multi(const int512_t& scalar) const;
static void round(int512_t& num, const int512_t& denom) ;
};
static void round(int512_t& num, const int512_t& denom);
};
static const lattice curve_lattice = {
static const lattice curve_lattice = {
.vectors_ = {
{
int512_t("147946756881789319000765030803803410728"),
@@ -35,37 +35,20 @@ namespace bn256 {
.det_ = int512_t("43776485743678550444492811490514550177096728800832068687396408373151616991234")
};
static const lattice target_lattice = {
.vectors_ = {
{
int512_t("9931322734385697761"),
int512_t("9931322734385697761"),
int512_t("9931322734385697763"),
int512_t("9931322734385697764")
},{
int512_t("4965661367192848881"),
int512_t("4965661367192848881"),
int512_t("4965661367192848882"),
int512_t("-9931322734385697762")
},{
int512_t("-9931322734385697762"),
int512_t("-4965661367192848881"),
int512_t("4965661367192848881"),
int512_t("-4965661367192848882")
},{
int512_t("9931322734385697763"),
int512_t("-4965661367192848881"),
int512_t("-4965661367192848881"),
int512_t("-4965661367192848881")
}
},
.inverse_ = {
int512_t("734653495049373973658254490726798021314063399421879442165"),
int512_t("147946756881789319000765030803803410728"),
int512_t("-147946756881789319005730692170996259609"),
int512_t("1469306990098747947464455738335385361643788813749140841702")
},
.det_ = constants::order
};
static const lattice target_lattice = {
.vectors_ = { { int512_t("9931322734385697761"), int512_t("9931322734385697761"), int512_t("9931322734385697763"),
int512_t("9931322734385697764") },
{ int512_t("4965661367192848881"), int512_t("4965661367192848881"), int512_t("4965661367192848882"),
int512_t("-9931322734385697762") },
{ int512_t("-9931322734385697762"), int512_t("-4965661367192848881"), int512_t("4965661367192848881"),
int512_t("-4965661367192848882") },
{ int512_t("9931322734385697763"), int512_t("-4965661367192848881"), int512_t("-4965661367192848881"),
int512_t("-4965661367192848881") } },
.inverse_ = { int512_t("734653495049373973658254490726798021314063399421879442165"),
int512_t("147946756881789319000765030803803410728"),
int512_t("-147946756881789319005730692170996259609"),
int512_t("1469306990098747947464455738335385361643788813749140841702") },
.det_ = constants::order
};
}
} // namespace bn256
+274 -306
View File
@@ -1,337 +1,305 @@
#include <optate.h>
#include <array>
#include <constants.h>
#include <optate.h>
#include <tuple>
namespace bn256 {
struct line_function_result_t {
gfp2 a_{};
gfp2 b_{};
gfp2 c_{};
twist_point out_{};
};
// struct line_function_result_t {
// gfp2 a_;
// gfp2 b_;
// gfp2 c_;
// twist_point out_;
// };
std::ostream& operator << (std::ostream& os, const line_function_result_t& lfr) {
return os << " a: " << lfr.a_ << ",\n b:" << lfr.b_ << ",\n c: " << lfr.c_ << ",\n out: " << lfr.out_ << "\n";
// std::ostream& operator<<(std::ostream& os, const line_function_result_t& lfr) {
// return os << " a: " << lfr.a_ << ",\n b:" << lfr.b_ << ",\n c: " << lfr.c_ << ",\n out: " << lfr.out_ << "\n";
// }
auto line_function_add(const twist_point& r, const twist_point& p, const curve_point& q, const gfp2& r2) noexcept {
// See the mixed addition algorithm from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
gfp2 B = p.x_.mul(r.t_);
gfp2 D = p.y_.add(r.z_);
D = D.square();
D = D.sub(r2);
D = D.sub(r.t_);
D = D.mul(r.t_);
gfp2 H = B.sub(r.x_);
gfp2 I = H.square();
gfp2 E = I.add(I);
E = E.add(E);
gfp2 J = H.mul(E);
gfp2 L1 = D.sub(r.y_);
L1 = L1.sub(r.y_);
gfp2 V = r.x_.mul(E);
twist_point rOut;
rOut.x_ = L1.square().sub(J).sub(V).sub(V);
rOut.z_ = r.z_.add(H).square().sub(r.t_).sub(I);
gfp2 t = V.sub(rOut.x_);
t = t.mul(L1);
gfp2 t2 = r.y_.mul(J);
t2 = t2.add(t2);
rOut.y_ = t.sub(t2);
rOut.t_ = rOut.z_.square();
t = p.y_.add(rOut.z_).square().sub(r2).sub(rOut.t_);
t2 = L1.mul(p.x_);
t2 = t2.add(t2);
gfp2 a = t2.sub(t);
gfp2 c = rOut.z_.mul_scalar(q.y_);
c = c.add(c);
gfp2 b{};
b = b.sub(L1);
b = b.mul_scalar(q.x_);
b = b.add(b);
return std::make_tuple(a, b, c, rOut);
}
auto line_function_double(const twist_point& r, const curve_point& q) noexcept {
// See the doubling algorithm for a=0 from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
gfp2 A = r.x_.square();
gfp2 B = r.y_.square();
gfp2 C = B.square();
gfp2 D = r.x_.add(B);
D = D.square();
D = D.sub(A);
D = D.sub(C);
D = D.add(D);
gfp2 E = A.add(A);
E = E.add(A);
gfp2 G = E.square();
twist_point rOut;
rOut.x_ = G.sub(D);
rOut.x_ = rOut.x_.sub(D);
rOut.z_ = r.y_.add(r.z_);
rOut.z_ = rOut.z_.square();
rOut.z_ = rOut.z_.sub(B);
rOut.z_ = rOut.z_.sub(r.t_);
rOut.y_ = D.sub(rOut.x_);
rOut.y_ = rOut.y_.mul(E);
gfp2 t = C.add(C);
t = t.add(t);
t = t.add(t);
rOut.y_ = rOut.y_.sub(t);
rOut.t_ = rOut.z_.square();
t = E.mul(r.t_);
t = t.add(t);
gfp2 b = {};
b = b.sub(t);
b = b.mul_scalar(q.x_);
gfp2 a = r.x_.add(E);
a = a.square();
a = a.sub(A);
a = a.sub(G);
t = B.add(B);
t = t.add(t);
a = a.sub(t);
gfp2 c = rOut.z_.mul(r.t_);
c = c.add(c);
c = c.mul_scalar(q.y_);
return std::make_tuple(a, b, c, rOut);
}
void mul_line(gfp12& ret, const gfp2& a, const gfp2& b, const gfp2& c) {
gfp6 a2{ gfp2::zero(), a, b };
a2 = a2.mul(ret.x_);
gfp6 t3 = ret.y_.mul_scalar(c);
gfp2 t = b.add(c);
gfp6 t2{ gfp2::zero(), a, t };
ret.x_ = ret.x_.add(ret.y_);
ret.y_ = t3;
ret.x_ = ret.x_.mul(t2);
ret.x_ = ret.x_.sub(a2);
ret.x_ = ret.x_.sub(ret.y_);
a2 = a2.mul_tau();
ret.y_ = ret.y_.add(a2);
}
// sixuPlus2NAF is 6u+2 in non-adjacent form.
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
gfp12 miller(const twist_point& q, const curve_point& p) noexcept {
gfp12 ret = gfp12::one();
twist_point a_affine = q.make_affine();
curve_point b_affine = p.make_affine();
twist_point minus_a = a_affine.neg();
twist_point r = a_affine;
gfp2 r2 = a_affine.y_.square();
for (auto i = six_u_plus_2_naf.size() - 1; i > 0; i--) {
auto [a, b, c, newR] = line_function_double(r, b_affine);
if (i != six_u_plus_2_naf.size() - 1) {
ret = ret.square();
}
mul_line(ret, a, b, c);
r = newR;
switch (six_u_plus_2_naf[i - 1]) {
case 1: std::tie(a, b, c, newR) = line_function_add(r, a_affine, b_affine, r2); break;
case -1: std::tie(a, b, c, newR) = line_function_add(r, minus_a, b_affine, r2); break;
default: continue;
}
mul_line(ret, a, b, c);
r = newR;
}
line_function_result_t
line_function_add(const twist_point& r, const twist_point& p, const curve_point& q, const gfp2& r2) {
line_function_result_t rc{};
gfp2 b{}, d{}, h{}, i{}, e{}, j{}, l1{}, v{}, t{}, t2{};
// In order to calculate Q1 we have to convert q from the sextic twist
// to the full GF(p^12) group, apply the Frobenius there, and convert
// back.
//
// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
// where x̄ is the conjugate of x. If we are going to apply the inverse
// isomorphism we need a value with a single coefficient of ω² so we
// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
// p, 2p-2 is a multiple of six. Therefore we can rewrite as
// x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
// ω².
//
// A similar argument can be made for the y value.
// See the mixed addition algorithm from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
b.mul(p.x_, r.t_);
twist_point q1;
q1.x_ = a_affine.x_.conjugate();
q1.x_ = q1.x_.mul(constants::xi_to_p_minus_1_over_3);
d.add(p.y_, r.z_);
d.square(d);
d.sub(d, r2);
d.sub(d, r.t_);
d.mul(d, r.t_);
q1.y_ = a_affine.y_.conjugate();
q1.y_ = q1.y_.mul(constants::xi_to_p_minus_1_over_2);
q1.z_.set_one();
q1.t_.set_one();
h.sub(b, r.x_);
i.square(h);
// For Q2 we are applying the p² Frobenius. The two conjugations cancel
// out and we are left only with the factors from the isomorphism. In
// the case of x, we end up with a pure number which is why
// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
// ignore this to end up with -Q2.
e.add(i, i);
e.add(e, e);
twist_point minus_q2;
minus_q2.x_ = a_affine.x_.mul_scalar(constants::xi_to_p_squared_minus_1_over_3);
minus_q2.y_ = a_affine.y_;
minus_q2.z_.set_one();
minus_q2.t_.set_one();
j.mul(h, e);
r2 = q1.y_.square();
auto [a, b, c, newR] = line_function_add(r, q1, b_affine, r2);
mul_line(ret, a, b, c);
r = newR;
l1.sub(d, r.y_);
l1.sub(l1, r.y_);
r2 = minus_q2.y_.square();
std::tie(a, b, c, newR) = line_function_add(r, minus_q2, b_affine, r2);
mul_line(ret, a, b, c);
r = newR;
v.mul(r.x_, e);
return ret;
}
rc.out_.x_.square(l1);
rc.out_.x_.sub(rc.out_.x_, j);
rc.out_.x_.sub(rc.out_.x_, v);
rc.out_.x_.sub(rc.out_.x_, v);
// finalExponentiation computes the (p¹²-1)/Order-th power of an element of
// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
// http://cryptojedi.org/papers/dclxvi-20100714.pdf)
gfp12 final_exponentiation(const gfp12& in) noexcept {
gfp12 t1;
rc.out_.z_.add(r.z_, h);
rc.out_.z_.square(rc.out_.z_);
rc.out_.z_.sub(rc.out_.z_, r.t_);
rc.out_.z_.sub(rc.out_.z_, i);
// This is the p^6-Frobenius
t1.x_ = in.x_.neg();
t1.y_ = in.y_;
t.sub(v, rc.out_.x_);
t.mul(t, l1);
t2.mul(r.y_, j);
t2.add(t2, t2);
rc.out_.y_.sub(t, t2);
gfp12 inv = in.invert();
t1 = t1.mul(inv);
rc.out_.t_.square(rc.out_.z_);
gfp12 t2 = t1.frobenius_p2();
t1 = t1.mul(t2);
t.add(p.y_, rc.out_.z_);
t.square(t);
t.sub(t, r2);
t.sub(t, rc.out_.t_);
gfp12 fp = t1.frobenius();
gfp12 fp2 = t1.frobenius_p2();
gfp12 fp3 = fp2.frobenius();
t2.mul(l1, p.x_);
t2.add(t2, t2);
rc.a_.sub(t2, t);
gfp12 fu = t1.exp(constants::u);
gfp12 fu2 = fu.exp(constants::u);
gfp12 fu3 = fu2.exp(constants::u);
rc.c_.mul_scalar(rc.out_.z_, q.y_);
rc.c_.add(rc.c_, rc.c_);
gfp12 y3 = fu.frobenius();
gfp12 fu2p = fu2.frobenius();
gfp12 fu3p = fu3.frobenius();
gfp12 y2 = fu2.frobenius_p2();
rc.b_.neg(l1);
rc.b_.mul_scalar(rc.b_, q.x_);
rc.b_.add(rc.b_, rc.b_);
gfp12 y0 = fp.mul(fp2);
y0 = y0.mul(fp3);
return rc;
}
gfp12 y1 = t1.conjugate();
gfp12 y5 = fu2.conjugate();
y3 = y3.conjugate();
gfp12 y4 = fu.mul(fu2p);
y4 = y4.conjugate();
line_function_result_t line_function_double(const twist_point& r, const curve_point& q) {
gfp12 y6 = fu3.mul(fu3p);
y6 = y6.conjugate();
line_function_result_t rc{};
gfp12 t0 = y6.square();
t0 = t0.mul(y4);
t0 = t0.mul(y5);
t1 = y3.mul(y5);
t1 = t1.mul(t0);
t0 = t0.mul(y2);
t1 = t1.square();
t1 = t1.mul(t0);
t1 = t1.square();
t0 = t1.mul(y1);
t1 = t1.mul(y0);
t0 = t0.square();
t0 = t0.mul(t1);
// See the doubling algorithm for a=0 from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
gfp2 a{}, b{}, c{}, d{}, e{}, g{}, t{};
return t0;
}
a.square(r.x_);
b.square(r.y_);
c.square(b);
gfp12 optimal_ate(const twist_point& a, const curve_point& b) noexcept {
auto e = miller(a, b);
auto ret = final_exponentiation(e);
d.add(r.x_, b);
d.square(d);
d.sub(d, a);
d.sub(d, c);
d.add(d, d);
e.add(a, a);
e.add(e, a);
g.square(e);
rc.out_.x_.sub(g, d);
rc.out_.x_.sub(rc.out_.x_, d);
rc.out_.z_.add(r.y_, r.z_);
rc.out_.z_.square(rc.out_.z_);
rc.out_.z_.sub(rc.out_.z_, b);
rc.out_.z_.sub(rc.out_.z_, r.t_);
rc.out_.y_.sub(d, rc.out_.x_);
rc.out_.y_.mul(rc.out_.y_, e);
t.add(c, c);
t.add(t, t);
t.add(t, t);
rc.out_.y_.sub(rc.out_.y_, t);
rc.out_.t_.square(rc.out_.z_);
t.mul(e, r.t_);
t.add(t, t);
rc.b_.neg(t);
rc.b_.mul_scalar(rc.b_, q.x_);
rc.a_.add(r.x_, e);
rc.a_.square(rc.a_);
rc.a_.sub(rc.a_, a);
rc.a_.sub(rc.a_, g);
t.add(b, b);
t.add(t, t);
rc.a_.sub(rc.a_, t);
rc.c_.mul(rc.out_.z_, r.t_);
rc.c_.add(rc.c_, rc.c_);
rc.c_.mul_scalar(rc.c_, q.y_);
return rc;
}
void mul_line(gfp12& ret, const gfp2& a, const gfp2& b, const gfp2& c) {
gfp6 a2{}, t2{}, t3{};
gfp2 t{};
a2.y_ = a;
a2.z_ = b;
a2.mul(a2, ret.x_);
t3.mul_scalar(ret.y_, c);
t.add(b, c);
t2.y_ = a;
t2.z_ = t;
ret.x_.add(ret.x_, ret.y_);
ret.y_ = t3;
ret.x_.mul(ret.x_, t2);
ret.x_.sub(ret.x_, a2);
ret.x_.sub(ret.x_, ret.y_);
a2.mul_tau(a2);
ret.y_.add(ret.y_, a2);
}
// sixuPlus2NAF is 6u+2 in non-adjacent form.
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
gfp12 miller(const twist_point& q, const curve_point& p) {
gfp12 ret{};
if (a.is_infinity() || b.is_infinity()) {
ret.set_one();
twist_point a_affine = q.make_affine();
curve_point b_affine = p.make_affine();
twist_point minus_a{}, r{};
minus_a.neg(a_affine);
r = a_affine;
gfp2 r2{};
r2.square(a_affine.y_);
for (auto i = six_u_plus_2_naf.size()-1; i > 0; i--) {
auto lf_result = line_function_double(r, b_affine);
if (i != six_u_plus_2_naf.size()-1) {
ret.square(ret);
}
mul_line(ret, lf_result.a_, lf_result.b_, lf_result.c_);
r = lf_result.out_;
switch (six_u_plus_2_naf[i-1]) {
case 1:
lf_result = line_function_add(r, a_affine, b_affine, r2);
break;
case -1:
lf_result = line_function_add(r, minus_a, b_affine, r2);
break;
default:
continue;
}
mul_line(ret, lf_result.a_, lf_result.b_, lf_result.c_);
r = lf_result.out_;
}
// In order to calculate Q1 we have to convert q from the sextic twist
// to the full GF(p^12) group, apply the Frobenius there, and convert
// back.
//
// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
// where x̄ is the conjugate of x. If we are going to apply the inverse
// isomorphism we need a value with a single coefficient of ω² so we
// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
// p, 2p-2 is a multiple of six. Therefore we can rewrite as
// x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
// ω².
//
// A similar argument can be made for the y value.
twist_point q1{};
q1.x_.conjugate(a_affine.x_);
q1.x_.mul(q1.x_, constants::xi_to_p_minus_1_over_3);
q1.y_.conjugate(a_affine.y_);
q1.y_.mul(q1.y_, constants::xi_to_p_minus_1_over_2);
q1.z_.set_one();
q1.t_.set_one();
// For Q2 we are applying the p² Frobenius. The two conjugations cancel
// out and we are left only with the factors from the isomorphism. In
// the case of x, we end up with a pure number which is why
// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
// ignore this to end up with -Q2.
twist_point minus_q2;
minus_q2.x_.mul_scalar(a_affine.x_, constants::xi_to_p_squared_minus_1_over_3);
minus_q2.y_ = a_affine.y_;
minus_q2.z_.set_one();
minus_q2.t_.set_one();
r2.square(q1.y_);
auto lf_result = line_function_add(r, q1, b_affine, r2);
mul_line(ret, lf_result.a_, lf_result.b_, lf_result.c_);
r = lf_result.out_;
r2.square(minus_q2.y_);
lf_result = line_function_add(r, minus_q2, b_affine, r2);
mul_line(ret, lf_result.a_, lf_result.b_, lf_result.c_);
r = lf_result.out_;
return ret;
}
// finalExponentiation computes the (p¹²-1)/Order-th power of an element of
// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
// http://cryptojedi.org/papers/dclxvi-20100714.pdf)
gfp12 final_exponentiation(const gfp12& in) {
gfp12 t1{}, inv{}, t2{}, fp{}, fp2{}, fp3{},
fu{}, fu2{}, fu3{}, y3{}, fu2p{}, fu3p{},
y2{}, y0{}, y1{}, y4{}, y5{}, y6{}, t0{};
// This is the p^6-Frobenius
t1.x_.neg(in.x_);
t1.y_ = in.y_;
inv.invert(in);
t1.mul(t1, inv);
t2.frobenius_p2(t1);
t1.mul(t1, t2);
fp.frobenius(t1);
fp2.frobenius_p2(t1);
fp3.frobenius(fp2);
fu.exp(t1, constants::u);
fu2.exp(fu, constants::u);
fu3.exp(fu2, constants::u);
y3.frobenius(fu);
fu2p.frobenius(fu2);
fu3p.frobenius(fu3);
y2.frobenius_p2(fu2);
y0.mul(fp, fp2);
y0.mul(y0, fp3);
y1.conjugate(t1);
y5.conjugate(fu2);
y3.conjugate(y3);
y4.mul(fu, fu2p);
y4.conjugate(y4);
y6.mul(fu3, fu3p);
y6.conjugate(y6);
t0.square(y6);
t0.mul(t0, y4);
t0.mul(t0, y5);
t1.mul(y3, y5);
t1.mul(t1, t0);
t0.mul(t0, y2);
t1.square(t1);
t1.mul(t1, t0);
t1.square(t1);
t0.mul(t1, y1);
t1.mul(t1, y0);
t0.square(t0);
t0.mul(t0, t1);
return t0;
}
gfp12 optimal_ate(const twist_point& a, const curve_point& b) {
auto e = miller(a, b);
auto ret = final_exponentiation(e);
if (a.is_infinity() || b.is_infinity()) {
ret.set_one();
}
return ret;
}
}
return ret;
}
} // namespace bn256
+3 -3
View File
@@ -7,9 +7,9 @@
namespace bn256 {
gfp12 miller(const twist_point& q, const curve_point& p);
gfp12 miller(const twist_point& q, const curve_point& p) noexcept;
gfp12 final_exponentiation(const gfp12& in);
gfp12 final_exponentiation(const gfp12& in) noexcept;
gfp12 optimal_ate(const twist_point& q, const curve_point& p);
gfp12 optimal_ate(const twist_point& q, const curve_point& p) noexcept;
}
+11 -14
View File
@@ -2,18 +2,15 @@
namespace bn256 {
random_256::random_256() {
using namespace boost::random;
uniform_int_distribution_ = uniform_int_distribution<uint256_t>(
std::numeric_limits<uint256_t>::min(),
std::numeric_limits<uint256_t>::max()/2);
std::random_device rd;
gen_ = generator(rd());
uniform_int_distribution_(gen_);
}
uint256_t random_256::sample() {
return uniform_int_distribution_(gen_);
}
random_256::random_256() {
using namespace boost::random;
uniform_int_distribution_ = uniform_int_distribution<uint256_t>(std::numeric_limits<uint256_t>::min(),
std::numeric_limits<uint256_t>::max() / 2);
std::random_device rd;
gen_ = generator(rd());
uniform_int_distribution_(gen_);
}
uint256_t random_256::sample() { return uniform_int_distribution_(gen_); }
} // namespace bn256
+14 -16
View File
@@ -1,26 +1,24 @@
#pragma once
#include <boost/multiprecision/cpp_int.hpp>
#include <random>
#include <boost/random.hpp>
#include <random>
namespace bn256 {
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
using namespace boost::random;
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
typedef independent_bits_engine<mt19937_64, std::numeric_limits<uint256_t>::digits, uint256_t> generator;
class random_256 {
public:
random_256();
class random_256 {
public:
random_256();
uint256_t sample();
uint256_t sample();
private:
uniform_int_distribution<uint256_t> uniform_int_distribution_;
generator gen_;
};
}
private:
using generator = boost::random::independent_bits_engine<boost::random::mt19937_64,
std::numeric_limits<uint256_t>::digits, uint256_t>;
boost::random::uniform_int_distribution<uint256_t> uniform_int_distribution_;
generator gen_;
};
} // namespace bn256
+164 -193
View File
@@ -1,209 +1,180 @@
#include <twist.h>
#include <constants.h>
#include <bitlen.h>
#include <constants.h>
#include <sstream>
#include <twist.h>
namespace bn256 {
constexpr gfp2 twist_b = {
{0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d},
{0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d},
};
constexpr gfp2 twist_b = {
{ 0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d },
{ 0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d },
};
std::string twist_point::string() const {
auto tmp = make_affine();
auto x = gfp2::gfp2_decode(tmp.x_);
auto y = gfp2::gfp2_decode(tmp.y_);
std::string twist_point::string() const {
auto tmp = make_affine();
auto x = gfp2::gfp2_decode(tmp.x_);
auto y = gfp2::gfp2_decode(tmp.y_);
std::string ret;
ret.reserve(265);
ret.append("(");
ret.append(x.string());
ret.append(", ");
ret.append(y.string());
ret.append(")");
return ret;
std::string ret;
ret.reserve(265);
ret.append("(");
ret.append(x.string());
ret.append(", ");
ret.append(y.string());
ret.append(")");
return ret;
}
bool twist_point::is_on_curve() const noexcept {
auto c = make_affine();
if (c.is_infinity()) {
return true;
}
bool twist_point::is_on_curve() {
auto c = make_affine();
if (c.is_infinity()) {
return true;
gfp2 y2 = c.y_.square();
gfp2 x3 = c.x_.square().mul(c.x_).add(twist_b);
if (y2 != x3)
return false;
twist_point cneg = c.mul(constants::order);
return cneg.z_.is_zero();
}
twist_point twist_point::add(const twist_point& b) const noexcept {
const twist_point& a = *this;
if (a.is_infinity()) {
return b;
}
if (b.is_infinity()) {
return a;
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
gfp2 z12 = a.z_.square();
gfp2 z22 = b.z_.square();
gfp2 u1 = a.x_.mul(z22);
gfp2 u2 = b.x_.mul(z12);
gfp2 t = b.z_.mul(z22);
gfp2 s1 = a.y_.mul(t);
t = a.z_.mul(z12);
gfp2 s2 = b.y_.mul(t);
gfp2 h = u2.sub(u1);
bool x_equal = h.is_zero();
t = h.add(h);
gfp2 i = t.square();
gfp2 j = h.mul(i);
t = s2.sub(s1);
bool y_equal = t.is_zero();
if (x_equal && y_equal) {
return a.double_();
}
gfp2 r = t.add(t);
gfp2 v = u1.mul(i);
twist_point c;
gfp2 t4 = r.square();
t = v.add(v);
gfp2 t6 = t4.sub(j);
c.x_ = t6.sub(t);
t = v.sub(c.x_); // t7
t4 = s1.mul(j); // t8
t6 = t4.add(t4); // t9
t4 = r.mul(t); // t10
c.y_ = t4.sub(t6);
t = a.z_.add(b.z_); // t11
t4 = t.square(); // t12
t = t4.sub(z12); // t13
t4 = t.sub(z22); // t14
c.z_ = t4.mul(h);
c.t_ = {};
return c;
}
twist_point twist_point::double_() const noexcept {
const twist_point& a = *this;
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
gfp2 A = a.x_.square();
gfp2 B = a.y_.square();
gfp2 C = B.square();
gfp2 t = a.x_.add(B);
gfp2 t2 = t.square();
t = t2.sub(A);
t2 = t.sub(C);
gfp2 d = t2.add(t2);
t = A.add(A);
gfp2 e = t.add(A);
gfp2 f = e.square();
twist_point c;
t = d.add(d);
c.x_ = f.sub(t);
c.z_ = a.y_.mul(a.z_);
c.z_ = c.z_.add(c.z_);
t = C.add(C);
t2 = t.add(t);
t = t2.add(t2);
c.y_ = d.sub(c.x_);
t2 = e.mul(c.y_);
c.y_ = t2.sub(t);
c.t_ = {};
return c;
}
twist_point twist_point::mul(const int512_t& scalar) const noexcept {
const twist_point& a = *this;
twist_point sum{}, t;
for (int i = bitlen(scalar); i >= 0; i--) {
t = sum.double_();
if (bit_test(scalar, i)) {
sum = t.add(a);
} else {
sum = t;
}
gfp2 y2{}, x3{};
y2.square(c.y_);
x3.square(c.x_);
x3.mul(x3, c.x_);
x3.add(x3, twist_b);
if (y2 != x3) {
return false;
}
twist_point cneg{};
cneg.mul(c, constants::order);
return cneg.z_.is_zero();
}
void twist_point::set_infinity() {
x_.set_zero();
y_.set_one();
z_.set_zero();
t_.set_zero();
return sum;
}
twist_point twist_point::make_affine() const noexcept {
if (z_.is_one()) {
return *this;
} else if (z_.is_zero()) {
return { gfp2::zero(), gfp2::one(), gfp2::zero() };
}
bool twist_point::is_infinity() const {
return z_.is_zero();
}
gfp2 z_inv = z_.invert();
gfp2 t = y_.mul(z_inv);
gfp2 z_inv2 = z_inv.square();
void twist_point::add(const twist_point& a, const twist_point& b) {
if (a.is_infinity()) {
*this = b;
return;
}
if (b.is_infinity()) {
*this = a;
return;
}
twist_point c;
c.y_ = t.mul(z_inv2);
t = x_.mul(z_inv2);
c.x_ = t;
c.z_.set_one();
c.t_.set_one();
return c;
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
gfp2 z12{};
z12.square(a.z_);
gfp2 z22{};
z22.square(b.z_);
gfp2 u1{};
u1.mul(a.x_, z22);
gfp2 u2{};
u2.mul(b.x_, z12);
gfp2 t{};
t.mul(b.z_, z22);
gfp2 s1{};
s1.mul(a.y_, t);
t.mul(a.z_, z12);
gfp2 s2{};
s2.mul(b.y_, t);
gfp2 h{};
h.sub(u2, u1);
bool x_equal = h.is_zero();
t.add(h, h);
gfp2 i{};
i.square(t);
gfp2 j{};
j.mul(h, i);
t.sub(s2, s1);
bool y_equal = t.is_zero();
if (x_equal && y_equal) {
double_(a);
return;
}
gfp2 r{};
r.add(t, t);
gfp2 v{};
v.mul(u1, i);
gfp2 t4{};
t4.square(r);
t.add(v, v);
gfp2 t6{};
t6.sub(t4, j);
x_.sub(t6, t);
t.sub(v, x_); // t7
t4.mul(s1, j); // t8
t6.add(t4, t4); // t9
t4.mul(r, t); // t10
y_.sub(t4, t6);
t.add(a.z_, b.z_); // t11
t4.square(t); // t12
t.sub(t4, z12); // t13
t4.sub(t, z22); // t14
z_.mul(t4, h);
}
void twist_point::double_(const twist_point& a) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
gfp2 A{};
A.square(a.x_);
gfp2 b{};
b.square(a.y_);
gfp2 c{};
c.square(b);
gfp2 t{};
t.add(a.x_, b);
gfp2 t2{};
t2.square(t);
t.sub(t2, A);
t2.sub(t, c);
gfp2 d{};
d.add(t2, t2);
t.add(A, A);
gfp2 e{};
e.add(t, A);
gfp2 f{};
f.square(e);
t.add(d, d);
x_.sub(f, t);
z_.mul(a.y_, a.z_);
z_.add(z_, z_);
t.add(c, c);
t2.add(t, t);
t.add(t2, t2);
y_.sub(d, x_);
t2.mul(e, y_);
y_.sub(t2, t);
}
void twist_point::mul(const twist_point& a, const int512_t& scalar) {
twist_point sum{}, t{};
for (int i = bitlen(scalar); i >= 0; i--) {
t.double_(sum);
if (bit_test(scalar, i)) {
sum.add(t, a);
} else {
sum = t;
}
}
*this = sum;
}
twist_point twist_point::make_affine() const {
if (z_.is_one()) {
return *this;
} else if (z_.is_zero()) {
return {};
}
gfp2 z_inv{}, t{}, z_inv2{};
z_inv.invert(z_);
t.mul(y_, z_inv);
z_inv2.square(z_inv);
twist_point result;
result.y_.mul(t, z_inv2);
t.mul(x_, z_inv2);
result.x_= t;
result.z_.set_one();
result.t_.set_one();
return result;
}
void twist_point::neg(const twist_point& a) {
x_ = a.x_;
y_.neg(a.y_);
z_ = a.z_;
t_.set_zero();
}
}
twist_point twist_point::neg() const noexcept {
const twist_point& a = *this;
return { a.x_, a.y_.neg(), a.z_, gfp2::zero() };
}
} // namespace bn256
+29 -24
View File
@@ -1,42 +1,47 @@
#pragma once
#include <gfp2.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <gfp2.h>
using boost::multiprecision::int512_t;
namespace bn256 {
// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are
// kept in Jacobian form and t=z² when valid. The group G₂ is the set of
// n-torsion points of this curve over GF(p²) (where n = Order)
struct twist_point {
gfp2 x_;
gfp2 y_;
gfp2 z_;
gfp2 t_;
// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are
// kept in Jacobian form and t=z² when valid. The group G₂ is the set of
// n-torsion points of this curve over GF(p²) (where n = Order)
struct twist_point {
gfp2 x_;
gfp2 y_;
gfp2 z_;
gfp2 t_;
std::string string() const ;
std::string string() const;
// IsOnCurve returns true iff c is on the curve.
bool is_on_curve();
// IsOnCurve returns true iff c is on the curve.
bool is_on_curve() const noexcept;
void set_infinity();
static constexpr twist_point infinity() noexcept { return { gfp2::zero(), gfp2::one(), gfp2::zero(), gfp2::zero() }; }
[[nodiscard]] bool is_infinity() const;
[[nodiscard]] bool is_infinity() const noexcept { return z_ == gfp2::zero(); }
void add(const twist_point& a, const twist_point& b);
twist_point add(const twist_point& b) const noexcept;
void double_(const twist_point& a);
twist_point double_() const noexcept;
void mul(const twist_point& a, const int512_t& scalar);
twist_point mul(const int512_t& scalar) const noexcept;
twist_point make_affine() const;
twist_point make_affine() const noexcept;
twist_point neg() const noexcept;
void neg(const twist_point& a);
};
inline std::ostream& operator << (std::ostream& os, const twist_point& v) {
return os << v.string();
bool operator==(const twist_point& rhs) const noexcept {
static_assert(std::is_standard_layout_v<twist_point>);
return memcmp(this, &rhs, sizeof(*this)) == 0;
}
}
bool operator!=(const twist_point& rhs) const noexcept { return !(*this == rhs); }
};
inline std::ostream& operator<<(std::ostream& os, const twist_point& v) { return os << v.string(); }
} // namespace bn256
+15 -43
View File
@@ -40,37 +40,12 @@ TEST_CASE("test bilinearity", "[bn256]"){
bn256::gt e1 = bn256::pair(p1, p2);
bn256::gt e2 = bn256::pair(c1, c2);
e2.scalar_mult(e2, a);
e2.scalar_mult(e2, b);
e2 = e2.scalar_mult(a);
e2 = e2.scalar_mult(b);
CHECK(e1 == e2);
}
}
static bn256::g1 test_marshal_g1(const int512_t& base) {
bn256::g1 ret, t1;
t1.scalar_base_mult(base);
auto m1 = t1.marshal();
auto ec = ret.unmarshal(m1);
REQUIRE(ec == std::error_code{});
return ret;
}
static bn256::g2 test_marshal_g2(const int512_t& base) {
bn256::g2 ret, t1;
t1.scalar_base_mult(base);
auto m1 = t1.marshal();
auto ec = ret.unmarshal(m1);
REQUIRE(ec == std::error_code{});
return ret;
}
static auto test_marshal_pair(const bn256::g1& a, const bn256::g2& b, const int512_t& base) {
auto pair = bn256::pair(a, b);
pair.scalar_mult(pair, base);
pair.marshal();
return pair;
}
TEST_CASE("test tripartite_diffie_hellman", "[bn256]"){
int a = rand();
@@ -80,29 +55,27 @@ TEST_CASE("test tripartite_diffie_hellman", "[bn256]"){
bn256::g1 pa, pb, pc;
bn256::g2 qa, qb, qc;
pa = test_marshal_g1(a);
qa = test_marshal_g2(a);
REQUIRE(pa.unmarshal(bn256::g1::scalar_base_mult(a).marshal()) == std::error_code{});
REQUIRE(qa.unmarshal(bn256::g2::scalar_base_mult(a).marshal()) == std::error_code{});
REQUIRE(pb.unmarshal(bn256::g1::scalar_base_mult(b).marshal()) == std::error_code{});
REQUIRE(qb.unmarshal(bn256::g2::scalar_base_mult(b).marshal()) == std::error_code{});
REQUIRE(pc.unmarshal(bn256::g1::scalar_base_mult(c).marshal()) == std::error_code{});
REQUIRE(qc.unmarshal(bn256::g2::scalar_base_mult(c).marshal()) == std::error_code{});
pb = test_marshal_g1(b);
qb = test_marshal_g2(b);
auto k1_bytes = bn256::pair(pb, qc).scalar_mult(a).marshal();
auto k2_bytes = bn256::pair(pc, qa).scalar_mult(b).marshal();
auto k3_bytes = bn256::pair(pa, qb).scalar_mult(c).marshal();
pc = test_marshal_g1(c);
qc = test_marshal_g2(c);
auto k1_bytes = test_marshal_pair(pb, qc, a);
auto k2_bytes = test_marshal_pair(pc, qa, b);
auto k3_bytes = test_marshal_pair(pa, qb, c);
CHECK(k1_bytes == k2_bytes);
CHECK(k2_bytes == k3_bytes);
}
TEST_CASE("test g2_self_addition", "[bn256]"){
int s = rand();
bn256::g2 p;
p.scalar_base_mult(s);
bn256::g2 p = bn256::g2::scalar_base_mult(s);
REQUIRE(p.p_.is_on_curve());
p.add(p, p);
p = p.add(p);
auto m = p.marshal();
CHECK( p.unmarshal(m) == std::error_code{});
}
@@ -111,8 +84,7 @@ TEST_CASE("test g2_self_addition", "[bn256]"){
TEST_CASE("test twist point mul", "[bn256]"){
const int512_t k("73391516005847081647776723068736393251206848701235344996976057911204818492439");
bn256::twist_point tp_gen(bn256::twist_gen);
bn256::g2 p;
p.scalar_base_mult(k);
bn256::g2 p = bn256::g2::scalar_base_mult(k);
const bn256::twist_point expected = {
{
@@ -128,5 +100,5 @@ TEST_CASE("test twist point mul", "[bn256]"){
{ bn256::new_gfp(0), bn256::new_gfp(0)}
};
CHECK(memcmp(&p, &expected, sizeof(p)) == 0);
CHECK(p.p_ == expected);
}
+12 -34
View File
@@ -1,32 +1,9 @@
#include <bn256.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <random_256.h>
#include <catch2/catch_test_macros.hpp>
#include <random_256.h>
using namespace boost::multiprecision::literals;
using namespace boost::multiprecision;
static bn256::g1 make_scaled_g1(const int512_t& scale_value) {
bn256::g1 ret;
ret.scalar_base_mult(scale_value);
return ret;
}
static bn256::g2 make_scaled_g2(const int512_t& scale_value) {
bn256::g2 ret;
ret.scalar_base_mult(scale_value);
return ret;
}
static bn256::gt make_scaled_pair(const bn256::g1& a, const bn256::g2& b, const int512_t& scale_value) {
bn256::gt ret = bn256::pair(a, b);
ret.scalar_mult(ret, scale_value);
return ret;
}
TEST_CASE("test example pair", "[example]"){
TEST_CASE("test example pair", "[example]") {
bn256::random_256 rand;
@@ -34,18 +11,19 @@ TEST_CASE("test example pair", "[example]"){
auto b = rand.sample();
auto c = rand.sample();
auto pa = make_scaled_g1(a);
auto qa = make_scaled_g2(a);
auto pa = bn256::g1::scalar_base_mult(a);
auto qa = bn256::g2::scalar_base_mult(a);
auto pb = make_scaled_g1(b);
auto qb = make_scaled_g2(b);
auto pb = bn256::g1::scalar_base_mult(b);
auto qb = bn256::g2::scalar_base_mult(b);
auto pc = make_scaled_g1(c);
auto qc = make_scaled_g2(c);
auto pc = bn256::g1::scalar_base_mult(c);
auto qc = bn256::g2::scalar_base_mult(c);
auto k1 = bn256::pair(pb, qc).scalar_mult(a);
auto k2 = bn256::pair(pc, qa).scalar_mult(b);
auto k3 = bn256::pair(pa, qb).scalar_mult(c);
auto k1 = make_scaled_pair(pb, qc, a);
auto k2 = make_scaled_pair(pc, qa, b);
auto k3 = make_scaled_pair(pa, qb, c);
CHECK(k1 == k2);
CHECK(k1 == k3);
}
+4
View File
@@ -50,4 +50,8 @@ TEST_CASE("test_gfp_mul", "[gfp]"){
bn256::gfp h{};
bn256::gfp_mul(h, a, b);
CHECK(h == w);
auto gfp1 = bn256::new_gfp(1);
std::cout << std::hex << gfp1[0] << "\n" << gfp1[1] << "\n" << gfp1[2] << "\n" << gfp1[3] << "\n";
}
+4 -9
View File
@@ -7,24 +7,19 @@ using namespace boost::multiprecision;
static bn256::g1 make_scaled_g1(const std::string& scale_string) {
bn256::g1 ret;
int512_t scale_value(scale_string);
ret.scalar_base_mult(scale_value);
return ret;
return bn256::g1::scalar_base_mult(scale_value);
}
static bn256::g2 make_scaled_g2(const std::string& scale_string) {
bn256::g2 ret;
int512_t scale_value(scale_string);
ret.scalar_base_mult(scale_value);
return ret;
return bn256::g2::scalar_base_mult(scale_value);
}
static bn256::gt make_scaled_gt(const bn256::gt& a, const std::string& scale_string) {
bn256::gt ret;
int512_t scale_value(scale_string);
ret.scalar_mult(a, scale_value);
return ret;
return a.scalar_mult(scale_value);
}
TEST_CASE("test_pairings", "[main]") {
@@ -53,7 +48,7 @@ TEST_CASE("test_pairings", "[main]") {
CHECK(bn256::pairing_check(g1_vec, g2_vec)); // MultiAte check gave false negative!
auto p0 = bn256::gt{};
p0.add(p1, pn1);
p0 = p1.add(pn1);
auto p0_2 = bn256::pair(a1, b0);
CHECK (p0.string() == p0_2.string()); // Pairing mismatch