mirror of
https://github.com/AntelopeIO/bn256.git
synced 2026-07-21 13:53:29 +00:00
refactor
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user