aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/byzantine-lab/mcl/include/mcl
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/byzantine-lab/mcl/include/mcl')
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/aggregate_sig.hpp265
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/ahe.hpp76
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/array.hpp167
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/bls12_381.hpp15
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/bn.h428
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/bn.hpp2261
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/bn256.hpp15
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/bn384.hpp15
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/bn512.hpp14
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/conversion.hpp495
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/curve_type.h35
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/ec.hpp1045
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/ecdsa.h105
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/ecdsa.hpp257
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/ecparam.hpp191
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/elgamal.hpp612
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/fp.hpp661
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/fp_tower.hpp1364
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/gmp_util.hpp954
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/impl/bn_c_impl.hpp643
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/lagrange.hpp107
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/op.hpp389
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/operator.hpp177
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/paillier.hpp84
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/randgen.hpp156
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/she.h270
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/she.hpp1939
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/util.hpp285
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/vint.hpp1987
-rw-r--r--vendor/github.com/byzantine-lab/mcl/include/mcl/window_method.hpp175
30 files changed, 15187 insertions, 0 deletions
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/aggregate_sig.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/aggregate_sig.hpp
new file mode 100644
index 000000000..f31405705
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/aggregate_sig.hpp
@@ -0,0 +1,265 @@
+#pragma once
+/**
+ @file
+ @brief aggregate signature
+ @author MITSUNARI Shigeo(@herumi)
+ see http://crypto.stanford.edu/~dabo/papers/aggreg.pdf
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <cmath>
+#include <vector>
+#include <iosfwd>
+#include <set>
+#ifndef MCLBN_FP_UNIT_SIZE
+ #define MCLBN_FP_UNIT_SIZE 4
+#endif
+#if MCLBN_FP_UNIT_SIZE == 4
+#include <mcl/bn256.hpp>
+namespace mcl {
+using namespace mcl::bn256;
+}
+#elif MCLBN_FP_UNIT_SIZE == 6
+#include <mcl/bn384.hpp>
+namespace mcl {
+using namespace mcl::bn384;
+}
+#elif MCLBN_FP_UNIT_SIZE == 8
+#include <mcl/bn512.hpp>
+namespace mcl {
+using namespace mcl::bn512;
+}
+#else
+ #error "MCLBN_FP_UNIT_SIZE must be 4, 6, or 8"
+#endif
+
+namespace mcl { namespace aggs {
+
+/*
+ AGGregate Signature Template class
+*/
+template<size_t dummyImpl = 0>
+struct AGGST {
+ typedef typename G1::BaseFp Fp;
+
+ class SecretKey;
+ class PublicKey;
+ class Signature;
+
+ static G1 P_;
+ static G2 Q_;
+ static std::vector<Fp6> Qcoeff_;
+public:
+ static void init(const mcl::CurveParam& cp = mcl::BN254)
+ {
+ initPairing(cp);
+ hashAndMapToG1(P_, "0");
+ hashAndMapToG2(Q_, "0");
+ precomputeG2(Qcoeff_, Q_);
+ }
+ class Signature : public fp::Serializable<Signature> {
+ G1 S_;
+ friend class SecretKey;
+ friend class PublicKey;
+ public:
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ S_.load(is, ioMode);
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ S_.save(os, ioMode);
+ }
+ friend std::istream& operator>>(std::istream& is, Signature& self)
+ {
+ self.load(is, fp::detectIoMode(G1::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const Signature& self)
+ {
+ self.save(os, fp::detectIoMode(G1::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const Signature& rhs) const
+ {
+ return S_ == rhs.S_;
+ }
+ bool operator!=(const Signature& rhs) const { return !operator==(rhs); }
+ /*
+ aggregate sig[0..n) and set *this
+ */
+ void aggregate(const Signature *sig, size_t n)
+ {
+ G1 S;
+ S.clear();
+ for (size_t i = 0; i < n; i++) {
+ S += sig[i].S_;
+ }
+ S_ = S;
+ }
+ void aggregate(const std::vector<Signature>& sig)
+ {
+ aggregate(sig.data(), sig.size());
+ }
+ /*
+ aggregate verification
+ */
+ bool verify(const void *const *msgVec, const size_t *sizeVec, const PublicKey *pubVec, size_t n) const
+ {
+ if (n == 0) return false;
+ typedef std::set<Fp> FpSet;
+ FpSet msgSet;
+ typedef std::vector<G1> G1Vec;
+ G1Vec hv(n);
+ for (size_t i = 0; i < n; i++) {
+ Fp h;
+ h.setHashOf(msgVec[i], sizeVec[i]);
+ std::pair<typename FpSet::iterator, bool> ret = msgSet.insert(h);
+ if (!ret.second) throw cybozu::Exception("aggs::verify:same msg");
+ mapToG1(hv[i], h);
+ }
+ /*
+ e(aggSig, xQ) = prod_i e(hv[i], pub[i].Q)
+ <=> finalExp(e(-aggSig, xQ) * prod_i millerLoop(hv[i], pub[i].xQ)) == 1
+ */
+ GT e1, e2;
+ precomputedMillerLoop(e1, -S_, Qcoeff_);
+ millerLoop(e2, hv[0], pubVec[0].xQ_);
+ for (size_t i = 1; i < n; i++) {
+ GT e;
+ millerLoop(e, hv[i], pubVec[i].xQ_);
+ e2 *= e;
+ }
+ e1 *= e2;
+ finalExp(e1, e1);
+ return e1.isOne();
+ }
+ bool verify(const std::vector<std::string>& msgVec, const std::vector<PublicKey>& pubVec) const
+ {
+ const size_t n = msgVec.size();
+ if (n != pubVec.size()) throw cybozu::Exception("aggs:Signature:verify:bad size") << msgVec.size() << pubVec.size();
+ if (n == 0) return false;
+ std::vector<const void*> mv(n);
+ std::vector<size_t> sv(n);
+ for (size_t i = 0; i < n; i++) {
+ mv[i] = msgVec[i].c_str();
+ sv[i] = msgVec[i].size();
+ }
+ return verify(&mv[0], &sv[0], &pubVec[0], n);
+ }
+ };
+ class PublicKey : public fp::Serializable<PublicKey> {
+ G2 xQ_;
+ friend class SecretKey;
+ friend class Signature;
+ public:
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ xQ_.load(is, ioMode);
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ xQ_.save(os, ioMode);
+ }
+ friend std::istream& operator>>(std::istream& is, PublicKey& self)
+ {
+ self.load(is, fp::detectIoMode(G2::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const PublicKey& self)
+ {
+ self.save(os, fp::detectIoMode(G2::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const PublicKey& rhs) const
+ {
+ return xQ_ == rhs.xQ_;
+ }
+ bool operator!=(const PublicKey& rhs) const { return !operator==(rhs); }
+ bool verify(const Signature& sig, const void *m, size_t mSize) const
+ {
+ /*
+ H = hash(m)
+ e(S, Q) = e(H, xQ) where S = xH
+ <=> e(S, Q)e(-H, xQ) = 1
+ <=> finalExp(millerLoop(S, Q)e(-H, x)) = 1
+ */
+ G1 H;
+ hashAndMapToG1(H, m, mSize);
+ G1::neg(H, H);
+ GT e1, e2;
+ precomputedMillerLoop(e1, sig.S_, Qcoeff_);
+ millerLoop(e2, H, xQ_);
+ e1 *= e2;
+ finalExp(e1, e1);
+ return e1.isOne();
+ }
+ bool verify(const Signature& sig, const std::string& m) const
+ {
+ return verify(sig, m.c_str(), m.size());
+ }
+ };
+ class SecretKey : public fp::Serializable<SecretKey> {
+ Fr x_;
+ friend class PublicKey;
+ friend class Signature;
+ public:
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ x_.load(is, ioMode);
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ x_.save(os, ioMode);
+ }
+ friend std::istream& operator>>(std::istream& is, SecretKey& self)
+ {
+ self.load(is, fp::detectIoMode(Fr::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const SecretKey& self)
+ {
+ self.save(os, fp::detectIoMode(Fr::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const SecretKey& rhs) const
+ {
+ return x_ == rhs.x_;
+ }
+ bool operator!=(const SecretKey& rhs) const { return !operator==(rhs); }
+ void init()
+ {
+ x_.setByCSPRNG();
+ }
+ void getPublicKey(PublicKey& pub) const
+ {
+ G2::mul(pub.xQ_, Q_, x_);
+ }
+ void sign(Signature& sig, const void *m, size_t mSize) const
+ {
+ hashAndMapToG1(sig.S_, m, mSize);
+ G1::mul(sig.S_, sig.S_, x_);
+ }
+ void sign(Signature& sig, const std::string& m) const
+ {
+ sign(sig, m.c_str(), m.size());
+ }
+ };
+};
+
+template<size_t dummyImpl> G1 AGGST<dummyImpl>::P_;
+template<size_t dummyImpl> G2 AGGST<dummyImpl>::Q_;
+template<size_t dummyImpl> std::vector<Fp6> AGGST<dummyImpl>::Qcoeff_;
+
+typedef AGGST<> AGGS;
+typedef AGGS::SecretKey SecretKey;
+typedef AGGS::PublicKey PublicKey;
+typedef AGGS::Signature Signature;
+
+} } // mcl::aggs
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/ahe.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/ahe.hpp
new file mode 100644
index 000000000..239319d0d
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/ahe.hpp
@@ -0,0 +1,76 @@
+#pragma once
+/**
+ @file
+ @brief 192/256-bit additive homomorphic encryption by lifted-ElGamal
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/elgamal.hpp>
+#include <mcl/ecparam.hpp>
+
+namespace mcl {
+
+#ifdef MCL_USE_AHE192
+namespace ahe192 {
+
+const mcl::EcParam& para = mcl::ecparam::NIST_P192;
+
+typedef mcl::FpT<mcl::FpTag, 192> Fp;
+typedef mcl::FpT<mcl::ZnTag, 192> Zn;
+typedef mcl::EcT<Fp> Ec;
+typedef mcl::ElgamalT<Ec, Zn> ElgamalEc;
+typedef ElgamalEc::PrivateKey SecretKey;
+typedef ElgamalEc::PublicKey PublicKey;
+typedef ElgamalEc::CipherText CipherText;
+
+static inline void initAhe()
+{
+ Fp::init(para.p);
+ Zn::init(para.n);
+ Ec::init(para.a, para.b);
+ Ec::setIoMode(16);
+ Zn::setIoMode(16);
+}
+
+static inline void initSecretKey(SecretKey& sec)
+{
+ const Ec P(Fp(para.gx), Fp(para.gy));
+ sec.init(P, Zn::getBitSize());
+}
+
+} //mcl::ahe192
+#endif
+
+#ifdef MCL_USE_AHE256
+namespace ahe256 {
+
+const mcl::EcParam& para = mcl::ecparam::NIST_P256;
+
+typedef mcl::FpT<mcl::FpTag, 256> Fp;
+typedef mcl::FpT<mcl::ZnTag, 256> Zn;
+typedef mcl::EcT<Fp> Ec;
+typedef mcl::ElgamalT<Ec, Zn> ElgamalEc;
+typedef ElgamalEc::PrivateKey SecretKey;
+typedef ElgamalEc::PublicKey PublicKey;
+typedef ElgamalEc::CipherText CipherText;
+
+static inline void initAhe()
+{
+ Fp::init(para.p);
+ Zn::init(para.n);
+ Ec::init(para.a, para.b);
+ Ec::setIoMode(16);
+ Zn::setIoMode(16);
+}
+
+static inline void initSecretKey(SecretKey& sec)
+{
+ const Ec P(Fp(para.gx), Fp(para.gy));
+ sec.init(P, Zn::getBitSize());
+}
+
+} //mcl::ahe256
+#endif
+
+} // mcl
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/array.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/array.hpp
new file mode 100644
index 000000000..a6d2a8fa3
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/array.hpp
@@ -0,0 +1,167 @@
+#pragma once
+/**
+ @file
+ @brief tiny vector class
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <stdlib.h>
+#include <stddef.h>
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+#include <new>
+#endif
+
+namespace mcl {
+
+template<class T>
+class Array {
+ T *p_;
+ size_t n_;
+ template<class U>
+ void swap_(U& x, U& y) const
+ {
+ U t;
+ t = x;
+ x = y;
+ y = t;
+ }
+public:
+ Array() : p_(0), n_(0) {}
+ ~Array()
+ {
+ free(p_);
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ Array(const Array& rhs)
+ : p_(0)
+ , n_(0)
+ {
+ if (rhs.n_ == 0) return;
+ p_ = (T*)malloc(sizeof(T) * rhs.n_);
+ if (p_ == 0) throw std::bad_alloc();
+ n_ = rhs.n_;
+ for (size_t i = 0; i < n_; i++) {
+ p_[i] = rhs.p_[i];
+ }
+ }
+ Array& operator=(const Array& rhs)
+ {
+ Array tmp(rhs);
+ tmp.swap(*this);
+ return *this;
+ }
+#endif
+ bool resize(size_t n)
+ {
+ if (n <= n_) {
+ n_ = n;
+ if (n == 0) {
+ free(p_);
+ p_ = 0;
+ }
+ return true;
+ }
+ T *q = (T*)malloc(sizeof(T) * n);
+ if (q == 0) return false;
+ for (size_t i = 0; i < n_; i++) {
+ q[i] = p_[i];
+ }
+ free(p_);
+ p_ = q;
+ n_ = n;
+ return true;
+ }
+ bool copy(const Array<T>& rhs)
+ {
+ if (this == &rhs) return true;
+ if (n_ < rhs.n_) {
+ clear();
+ if (!resize(rhs.n_)) return false;
+ }
+ for (size_t i = 0; i < rhs.n_; i++) {
+ p_[i] = rhs.p_[i];
+ }
+ n_ = rhs.n_;
+ return true;
+ }
+ void clear()
+ {
+ free(p_);
+ p_ = 0;
+ n_ = 0;
+ }
+ size_t size() const { return n_; }
+ void swap(Array<T>& rhs)
+ {
+ swap_(p_, rhs.p_);
+ swap_(n_, rhs.n_);
+ }
+ T& operator[](size_t n) { return p_[n]; }
+ const T& operator[](size_t n) const { return p_[n]; }
+ T* data() { return p_; }
+ const T* data() const { return p_; }
+};
+
+template<class T, size_t maxSize>
+class FixedArray {
+ T p_[maxSize];
+ size_t n_;
+ FixedArray(const FixedArray&);
+ void operator=(const FixedArray&);
+ template<class U>
+ void swap_(U& x, U& y) const
+ {
+ U t;
+ t = x;
+ x = y;
+ y = t;
+ }
+public:
+ FixedArray() : n_(0) {}
+ bool resize(size_t n)
+ {
+ if (n > maxSize) return false;
+ n_ = n;
+ return true;
+ }
+ bool copy(const FixedArray<T, maxSize>& rhs)
+ {
+ if (this == &rhs) return true;
+ for (size_t i = 0; i < rhs.n_; i++) {
+ p_[i] = rhs.p_[i];
+ }
+ n_ = rhs.n_;
+ return true;
+ }
+ void clear()
+ {
+ n_ = 0;
+ }
+ size_t size() const { return n_; }
+ void swap(FixedArray<T, maxSize>& rhs)
+ {
+ T *minP = p_;
+ size_t minN = n_;
+ T *maxP = rhs.p_;
+ size_t maxN = rhs.n_;
+ if (minP > maxP) {
+ swap_(minP, maxP);
+ swap_(minN, maxN);
+ }
+ for (size_t i = 0; i < minN; i++) {
+ swap_(minP[i], maxP[i]);
+ }
+ for (size_t i = minN; i < maxN; i++) {
+ minP[i] = maxP[i];
+ }
+ swap_(n_, rhs.n_);
+ }
+ T& operator[](size_t n) { return p_[n]; }
+ const T& operator[](size_t n) const { return p_[n]; }
+ T* data() { return p_; }
+ const T* data() const { return p_; }
+};
+
+} // mcl
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/bls12_381.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/bls12_381.hpp
new file mode 100644
index 000000000..316e142af
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/bls12_381.hpp
@@ -0,0 +1,15 @@
+#pragma once
+/**
+ @file
+ @brief preset class for BLS12-381 pairing
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#define MCL_MAX_FP_BIT_SIZE 384
+#define MCL_MAX_FR_BIT_SIZE 256
+#include <mcl/bn.hpp>
+
+namespace mcl { namespace bls12 {
+using namespace mcl::bn;
+} }
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/bn.h b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn.h
new file mode 100644
index 000000000..0a31d5501
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn.h
@@ -0,0 +1,428 @@
+#pragma once
+/**
+ @file
+ @brief C interface of 256/384-bit optimal ate pairing over BN curves
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+/*
+ the order of an elliptic curve over Fp is Fr
+*/
+#ifndef MCLBN_FP_UNIT_SIZE
+ #error "define MCLBN_FP_UNIT_SIZE 4(, 6 or 8)"
+#endif
+#ifndef MCLBN_FR_UNIT_SIZE
+ #define MCLBN_FR_UNIT_SIZE MCLBN_FP_UNIT_SIZE
+#endif
+#define MCLBN_COMPILED_TIME_VAR ((MCLBN_FR_UNIT_SIZE) * 10 + (MCLBN_FP_UNIT_SIZE))
+
+#include <stdint.h> // for uint64_t, uint8_t
+#include <stdlib.h> // for size_t
+
+
+#if defined(_MSC_VER)
+ #ifdef MCLBN_DONT_EXPORT
+ #define MCLBN_DLL_API
+ #else
+ #ifdef MCLBN_DLL_EXPORT
+ #define MCLBN_DLL_API __declspec(dllexport)
+ #else
+ #define MCLBN_DLL_API __declspec(dllimport)
+ #endif
+ #endif
+ #ifndef MCLBN_NO_AUTOLINK
+ #if MCLBN_FP_UNIT_SIZE == 4
+ #pragma comment(lib, "mclbn256.lib")
+ #elif MCLBN_FP_UNIT_SIZE == 6
+ #pragma comment(lib, "mclbn384.lib")
+ #else
+ #pragma comment(lib, "mclbn512.lib")
+ #endif
+ #endif
+#elif defined(__EMSCRIPTEN__) && !defined(MCLBN_DONT_EXPORT)
+ #define MCLBN_DLL_API __attribute__((used))
+#elif defined(__wasm__) && !defined(MCLBN_DONT_EXPORT)
+ #define MCLBN_DLL_API __attribute__((visibility("default")))
+#else
+ #define MCLBN_DLL_API
+#endif
+
+#ifdef __EMSCRIPTEN__
+ // avoid 64-bit integer
+ #define mclSize unsigned int
+ #define mclInt int
+#else
+ // use #define for cgo
+ #define mclSize size_t
+ #define mclInt int64_t
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef MCLBN_NOT_DEFINE_STRUCT
+
+typedef struct mclBnFr mclBnFr;
+typedef struct mclBnG1 mclBnG1;
+typedef struct mclBnG2 mclBnG2;
+typedef struct mclBnGT mclBnGT;
+typedef struct mclBnFp mclBnFp;
+typedef struct mclBnFp2 mclBnFp2;
+
+#else
+
+typedef struct {
+ uint64_t d[MCLBN_FR_UNIT_SIZE];
+} mclBnFr;
+
+typedef struct {
+ uint64_t d[MCLBN_FP_UNIT_SIZE * 3];
+} mclBnG1;
+
+typedef struct {
+ uint64_t d[MCLBN_FP_UNIT_SIZE * 2 * 3];
+} mclBnG2;
+
+typedef struct {
+ uint64_t d[MCLBN_FP_UNIT_SIZE * 12];
+} mclBnGT;
+
+typedef struct {
+ uint64_t d[MCLBN_FP_UNIT_SIZE];
+} mclBnFp;
+
+typedef struct {
+ mclBnFp d[2];
+} mclBnFp2;
+
+#endif
+
+#include <mcl/curve_type.h>
+
+#define MCLBN_IO_SERIALIZE_HEX_STR 2048
+// for backword compatibility
+enum {
+ mclBn_CurveFp254BNb = 0,
+ mclBn_CurveFp382_1 = 1,
+ mclBn_CurveFp382_2 = 2,
+ mclBn_CurveFp462 = 3,
+ mclBn_CurveSNARK1 = 4,
+ mclBls12_CurveFp381 = 5
+};
+
+// return 0xABC which means A.BC
+MCLBN_DLL_API int mclBn_getVersion();
+/*
+ init library
+ @param curve [in] type of bn curve
+ @param compiledTimeVar [in] specify MCLBN_COMPILED_TIME_VAR,
+ which macro is used to make sure that the values
+ are the same when the library is built and used
+ @return 0 if success
+ curve = BN254/BN_SNARK1 is allowed if maxUnitSize = 4
+ curve = BN381_1/BN381_2/BLS12_381 are allowed if maxUnitSize = 6
+ This parameter is used to detect a library compiled with different MCLBN_FP_UNIT_SIZE for safety.
+ @note not threadsafe
+ @note BN_init is used in libeay32
+*/
+MCLBN_DLL_API int mclBn_init(int curve, int compiledTimeVar);
+
+
+/*
+ pairing : G1 x G2 -> GT
+ #G1 = #G2 = r
+ G1 is a curve defined on Fp
+
+ serialized size of elements
+ |Fr| |Fp|
+ BN254 32 32
+ BN381 48 48
+ BLS12_381 32 48
+ BN462 58 58
+ |G1| = |Fp|
+ |G2| = |G1| * 2
+ |GT| = |G1| * 12
+*/
+/*
+ return the num of Unit(=uint64_t) to store Fr
+*/
+MCLBN_DLL_API int mclBn_getOpUnitSize(void);
+
+/*
+ return bytes for serialized G1(=Fp)
+*/
+MCLBN_DLL_API int mclBn_getG1ByteSize(void);
+/*
+ return bytes for serialized Fr
+*/
+MCLBN_DLL_API int mclBn_getFrByteSize(void);
+/*
+ return bytes for serialized Fp
+*/
+MCLBN_DLL_API int mclBn_getFpByteSize(void);
+
+/*
+ return decimal string of the order of the curve(=the characteristic of Fr)
+ return str(buf) if success
+*/
+MCLBN_DLL_API mclSize mclBn_getCurveOrder(char *buf, mclSize maxBufSize);
+
+/*
+ return decimal string of the characteristic of Fp
+ return str(buf) if success
+*/
+MCLBN_DLL_API mclSize mclBn_getFieldOrder(char *buf, mclSize maxBufSize);
+
+////////////////////////////////////////////////
+/*
+ deserialize
+ return read size if success else 0
+*/
+MCLBN_DLL_API mclSize mclBnFr_deserialize(mclBnFr *x, const void *buf, mclSize bufSize);
+MCLBN_DLL_API mclSize mclBnG1_deserialize(mclBnG1 *x, const void *buf, mclSize bufSize);
+MCLBN_DLL_API mclSize mclBnG2_deserialize(mclBnG2 *x, const void *buf, mclSize bufSize);
+MCLBN_DLL_API mclSize mclBnGT_deserialize(mclBnGT *x, const void *buf, mclSize bufSize);
+MCLBN_DLL_API mclSize mclBnFp_deserialize(mclBnFp *x, const void *buf, mclSize bufSize);
+MCLBN_DLL_API mclSize mclBnFp2_deserialize(mclBnFp2 *x, const void *buf, mclSize bufSize);
+
+/*
+ serialize
+ return written byte if sucess else 0
+*/
+MCLBN_DLL_API mclSize mclBnFr_serialize(void *buf, mclSize maxBufSize, const mclBnFr *x);
+MCLBN_DLL_API mclSize mclBnG1_serialize(void *buf, mclSize maxBufSize, const mclBnG1 *x);
+MCLBN_DLL_API mclSize mclBnG2_serialize(void *buf, mclSize maxBufSize, const mclBnG2 *x);
+MCLBN_DLL_API mclSize mclBnGT_serialize(void *buf, mclSize maxBufSize, const mclBnGT *x);
+MCLBN_DLL_API mclSize mclBnFp_serialize(void *buf, mclSize maxBufSize, const mclBnFp *x);
+MCLBN_DLL_API mclSize mclBnFp2_serialize(void *buf, mclSize maxBufSize, const mclBnFp2 *x);
+
+/*
+ set string
+ ioMode
+ 10 : decimal number
+ 16 : hexadecimal number
+ MCLBN_IO_SERIALIZE_HEX_STR : hex string of serialized data
+ return 0 if success else -1
+*/
+MCLBN_DLL_API int mclBnFr_setStr(mclBnFr *x, const char *buf, mclSize bufSize, int ioMode);
+MCLBN_DLL_API int mclBnG1_setStr(mclBnG1 *x, const char *buf, mclSize bufSize, int ioMode);
+MCLBN_DLL_API int mclBnG2_setStr(mclBnG2 *x, const char *buf, mclSize bufSize, int ioMode);
+MCLBN_DLL_API int mclBnGT_setStr(mclBnGT *x, const char *buf, mclSize bufSize, int ioMode);
+MCLBN_DLL_API int mclBnFp_setStr(mclBnFp *x, const char *buf, mclSize bufSize, int ioMode);
+
+/*
+ buf is terminated by '\0'
+ return strlen(buf) if sucess else 0
+*/
+MCLBN_DLL_API mclSize mclBnFr_getStr(char *buf, mclSize maxBufSize, const mclBnFr *x, int ioMode);
+MCLBN_DLL_API mclSize mclBnG1_getStr(char *buf, mclSize maxBufSize, const mclBnG1 *x, int ioMode);
+MCLBN_DLL_API mclSize mclBnG2_getStr(char *buf, mclSize maxBufSize, const mclBnG2 *x, int ioMode);
+MCLBN_DLL_API mclSize mclBnGT_getStr(char *buf, mclSize maxBufSize, const mclBnGT *x, int ioMode);
+MCLBN_DLL_API mclSize mclBnFp_getStr(char *buf, mclSize maxBufSize, const mclBnFp *x, int ioMode);
+
+// set zero
+MCLBN_DLL_API void mclBnFr_clear(mclBnFr *x);
+MCLBN_DLL_API void mclBnFp_clear(mclBnFp *x);
+MCLBN_DLL_API void mclBnFp2_clear(mclBnFp2 *x);
+
+// set x to y
+MCLBN_DLL_API void mclBnFr_setInt(mclBnFr *y, mclInt x);
+MCLBN_DLL_API void mclBnFr_setInt32(mclBnFr *y, int x);
+
+// x = buf & (1 << bitLen(r)) - 1
+// if (x >= r) x &= (1 << (bitLen(r) - 1)) - 1
+// always return 0
+MCLBN_DLL_API int mclBnFr_setLittleEndian(mclBnFr *x, const void *buf, mclSize bufSize);
+MCLBN_DLL_API int mclBnFp_setLittleEndian(mclBnFp *x, const void *buf, mclSize bufSize);
+
+// set (buf mod r) to x
+// return 0 if bufSize <= (byte size of Fr * 2) else -1
+MCLBN_DLL_API int mclBnFr_setLittleEndianMod(mclBnFr *x, const void *buf, mclSize bufSize);
+// set (buf mod p) to x
+// return 0 if bufSize <= (byte size of Fp * 2) else -1
+MCLBN_DLL_API int mclBnFp_setLittleEndianMod(mclBnFp *x, const void *buf, mclSize bufSize);
+
+// return 1 if true and 0 otherwise
+MCLBN_DLL_API int mclBnFr_isValid(const mclBnFr *x);
+MCLBN_DLL_API int mclBnFr_isEqual(const mclBnFr *x, const mclBnFr *y);
+MCLBN_DLL_API int mclBnFr_isZero(const mclBnFr *x);
+MCLBN_DLL_API int mclBnFr_isOne(const mclBnFr *x);
+
+MCLBN_DLL_API int mclBnFp_isEqual(const mclBnFp *x, const mclBnFp *y);
+MCLBN_DLL_API int mclBnFp2_isEqual(const mclBnFp2 *x, const mclBnFp2 *y);
+
+#ifndef MCL_DONT_USE_CSRPNG
+// return 0 if success
+MCLBN_DLL_API int mclBnFr_setByCSPRNG(mclBnFr *x);
+
+/*
+ set user-defined random function for setByCSPRNG
+ @param self [in] user-defined pointer
+ @param readFunc [in] user-defined function,
+ which writes random bufSize bytes to buf and returns bufSize if success else returns 0
+ @note if self == 0 and readFunc == 0 then set default random function
+ @note not threadsafe
+*/
+MCLBN_DLL_API void mclBn_setRandFunc(void *self, unsigned int (*readFunc)(void *self, void *buf, unsigned int bufSize));
+#endif
+
+// hash(s) and set x
+// return 0 if success
+MCLBN_DLL_API int mclBnFr_setHashOf(mclBnFr *x, const void *buf, mclSize bufSize);
+MCLBN_DLL_API int mclBnFp_setHashOf(mclBnFp *x, const void *buf, mclSize bufSize);
+
+// map x to y
+// return 0 if success else -1
+MCLBN_DLL_API int mclBnFp_mapToG1(mclBnG1 *y, const mclBnFp *x);
+MCLBN_DLL_API int mclBnFp2_mapToG2(mclBnG2 *y, const mclBnFp2 *x);
+
+MCLBN_DLL_API void mclBnFr_neg(mclBnFr *y, const mclBnFr *x);
+MCLBN_DLL_API void mclBnFr_inv(mclBnFr *y, const mclBnFr *x);
+MCLBN_DLL_API void mclBnFr_sqr(mclBnFr *y, const mclBnFr *x);
+MCLBN_DLL_API void mclBnFr_add(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);
+MCLBN_DLL_API void mclBnFr_sub(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);
+MCLBN_DLL_API void mclBnFr_mul(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);
+MCLBN_DLL_API void mclBnFr_div(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);
+
+////////////////////////////////////////////////
+// set zero
+MCLBN_DLL_API void mclBnG1_clear(mclBnG1 *x);
+
+
+// return 1 if true and 0 otherwise
+MCLBN_DLL_API int mclBnG1_isValid(const mclBnG1 *x);
+MCLBN_DLL_API int mclBnG1_isEqual(const mclBnG1 *x, const mclBnG1 *y);
+MCLBN_DLL_API int mclBnG1_isZero(const mclBnG1 *x);
+/*
+ return 1 if x has a correct order
+ x is valid point of G1 if and only if
+ mclBnG1_isValid() is true, which contains mclBnG1_isValidOrder() if mclBn_verifyOrderG1(true)
+ mclBnG1_isValid() && mclBnG1_isValidOrder() is true if mclBn_verifyOrderG1(false)
+*/
+MCLBN_DLL_API int mclBnG1_isValidOrder(const mclBnG1 *x);
+
+MCLBN_DLL_API int mclBnG1_hashAndMapTo(mclBnG1 *x, const void *buf, mclSize bufSize);
+
+
+MCLBN_DLL_API void mclBnG1_neg(mclBnG1 *y, const mclBnG1 *x);
+MCLBN_DLL_API void mclBnG1_dbl(mclBnG1 *y, const mclBnG1 *x);
+MCLBN_DLL_API void mclBnG1_normalize(mclBnG1 *y, const mclBnG1 *x);
+MCLBN_DLL_API void mclBnG1_add(mclBnG1 *z, const mclBnG1 *x, const mclBnG1 *y);
+MCLBN_DLL_API void mclBnG1_sub(mclBnG1 *z, const mclBnG1 *x, const mclBnG1 *y);
+MCLBN_DLL_API void mclBnG1_mul(mclBnG1 *z, const mclBnG1 *x, const mclBnFr *y);
+
+/*
+ constant time mul
+*/
+MCLBN_DLL_API void mclBnG1_mulCT(mclBnG1 *z, const mclBnG1 *x, const mclBnFr *y);
+
+////////////////////////////////////////////////
+// set zero
+MCLBN_DLL_API void mclBnG2_clear(mclBnG2 *x);
+
+// return 1 if true and 0 otherwise
+MCLBN_DLL_API int mclBnG2_isValid(const mclBnG2 *x);
+MCLBN_DLL_API int mclBnG2_isEqual(const mclBnG2 *x, const mclBnG2 *y);
+MCLBN_DLL_API int mclBnG2_isZero(const mclBnG2 *x);
+// return 1 if x has a correct order
+MCLBN_DLL_API int mclBnG2_isValidOrder(const mclBnG2 *x);
+
+MCLBN_DLL_API int mclBnG2_hashAndMapTo(mclBnG2 *x, const void *buf, mclSize bufSize);
+
+// return written size if sucess else 0
+
+MCLBN_DLL_API void mclBnG2_neg(mclBnG2 *y, const mclBnG2 *x);
+MCLBN_DLL_API void mclBnG2_dbl(mclBnG2 *y, const mclBnG2 *x);
+MCLBN_DLL_API void mclBnG2_normalize(mclBnG2 *y, const mclBnG2 *x);
+MCLBN_DLL_API void mclBnG2_add(mclBnG2 *z, const mclBnG2 *x, const mclBnG2 *y);
+MCLBN_DLL_API void mclBnG2_sub(mclBnG2 *z, const mclBnG2 *x, const mclBnG2 *y);
+MCLBN_DLL_API void mclBnG2_mul(mclBnG2 *z, const mclBnG2 *x, const mclBnFr *y);
+/*
+ constant time mul
+*/
+MCLBN_DLL_API void mclBnG2_mulCT(mclBnG2 *z, const mclBnG2 *x, const mclBnFr *y);
+
+////////////////////////////////////////////////
+// set zero
+MCLBN_DLL_API void mclBnGT_clear(mclBnGT *x);
+// set x to y
+MCLBN_DLL_API void mclBnGT_setInt(mclBnGT *y, mclInt x);
+MCLBN_DLL_API void mclBnGT_setInt32(mclBnGT *y, int x);
+
+// return 1 if true and 0 otherwise
+MCLBN_DLL_API int mclBnGT_isEqual(const mclBnGT *x, const mclBnGT *y);
+MCLBN_DLL_API int mclBnGT_isZero(const mclBnGT *x);
+MCLBN_DLL_API int mclBnGT_isOne(const mclBnGT *x);
+
+MCLBN_DLL_API void mclBnGT_neg(mclBnGT *y, const mclBnGT *x);
+MCLBN_DLL_API void mclBnGT_inv(mclBnGT *y, const mclBnGT *x);
+MCLBN_DLL_API void mclBnGT_sqr(mclBnGT *y, const mclBnGT *x);
+MCLBN_DLL_API void mclBnGT_add(mclBnGT *z, const mclBnGT *x, const mclBnGT *y);
+MCLBN_DLL_API void mclBnGT_sub(mclBnGT *z, const mclBnGT *x, const mclBnGT *y);
+MCLBN_DLL_API void mclBnGT_mul(mclBnGT *z, const mclBnGT *x, const mclBnGT *y);
+MCLBN_DLL_API void mclBnGT_div(mclBnGT *z, const mclBnGT *x, const mclBnGT *y);
+
+/*
+ pow for all elements of Fp12
+*/
+MCLBN_DLL_API void mclBnGT_powGeneric(mclBnGT *z, const mclBnGT *x, const mclBnFr *y);
+/*
+ pow for only {x|x^r = 1} in Fp12 by GLV method
+ the value generated by pairing satisfies the condition
+*/
+MCLBN_DLL_API void mclBnGT_pow(mclBnGT *z, const mclBnGT *x, const mclBnFr *y);
+
+MCLBN_DLL_API void mclBn_pairing(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y);
+MCLBN_DLL_API void mclBn_finalExp(mclBnGT *y, const mclBnGT *x);
+MCLBN_DLL_API void mclBn_millerLoop(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y);
+
+// return precomputedQcoeffSize * sizeof(Fp6) / sizeof(uint64_t)
+MCLBN_DLL_API int mclBn_getUint64NumToPrecompute(void);
+
+// allocate Qbuf[MCLBN_getUint64NumToPrecompute()] before calling this
+MCLBN_DLL_API void mclBn_precomputeG2(uint64_t *Qbuf, const mclBnG2 *Q);
+
+MCLBN_DLL_API void mclBn_precomputedMillerLoop(mclBnGT *f, const mclBnG1 *P, const uint64_t *Qbuf);
+MCLBN_DLL_API void mclBn_precomputedMillerLoop2(mclBnGT *f, const mclBnG1 *P1, const uint64_t *Q1buf, const mclBnG1 *P2, const uint64_t *Q2buf);
+MCLBN_DLL_API void mclBn_precomputedMillerLoop2mixed(mclBnGT *f, const mclBnG1 *P1, const mclBnG2 *Q1, const mclBnG1 *P2, const uint64_t *Q2buf);
+
+/*
+ Lagrange interpolation
+ recover out = y(0) by { (xVec[i], yVec[i]) }
+ return 0 if success else -1
+ @note *out = yVec[0] if k = 1
+ @note k >= 2, xVec[i] != 0, xVec[i] != xVec[j] for i != j
+*/
+MCLBN_DLL_API int mclBn_FrLagrangeInterpolation(mclBnFr *out, const mclBnFr *xVec, const mclBnFr *yVec, mclSize k);
+MCLBN_DLL_API int mclBn_G1LagrangeInterpolation(mclBnG1 *out, const mclBnFr *xVec, const mclBnG1 *yVec, mclSize k);
+MCLBN_DLL_API int mclBn_G2LagrangeInterpolation(mclBnG2 *out, const mclBnFr *xVec, const mclBnG2 *yVec, mclSize k);
+
+/*
+ evaluate polynomial
+ out = f(x) = c[0] + c[1] * x + c[2] * x^2 + ... + c[cSize - 1] * x^(cSize - 1)
+ @note cSize >= 2
+*/
+MCLBN_DLL_API int mclBn_FrEvaluatePolynomial(mclBnFr *out, const mclBnFr *cVec, mclSize cSize, const mclBnFr *x);
+MCLBN_DLL_API int mclBn_G1EvaluatePolynomial(mclBnG1 *out, const mclBnG1 *cVec, mclSize cSize, const mclBnFr *x);
+MCLBN_DLL_API int mclBn_G2EvaluatePolynomial(mclBnG2 *out, const mclBnG2 *cVec, mclSize cSize, const mclBnFr *x);
+
+/*
+ verify whether a point of an elliptic curve has order r
+ This api affetcs setStr(), deserialize() for G2 on BN or G1/G2 on BLS12
+ @param doVerify [in] does not verify if zero(default 1)
+*/
+MCLBN_DLL_API void mclBn_verifyOrderG1(int doVerify);
+MCLBN_DLL_API void mclBn_verifyOrderG2(int doVerify);
+
+/*
+ EXPERIMENTAL
+ only for curve = MCL_SECP* or MCL_NIST*
+ return standard base point of the current elliptic curve
+*/
+MCLBN_DLL_API int mclBnG1_getBasePoint(mclBnG1 *x);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/bn.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn.hpp
new file mode 100644
index 000000000..5ebe5d956
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn.hpp
@@ -0,0 +1,2261 @@
+#pragma once
+/**
+ @file
+ @brief optimal ate pairing over BN-curve / BLS12-curve
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/fp_tower.hpp>
+#include <mcl/ec.hpp>
+#include <mcl/curve_type.h>
+#include <assert.h>
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+#include <vector>
+#endif
+
+/*
+ set bit size of Fp and Fr
+*/
+#ifndef MCL_MAX_FP_BIT_SIZE
+ #define MCL_MAX_FP_BIT_SIZE 256
+#endif
+
+#ifndef MCL_MAX_FR_BIT_SIZE
+ #define MCL_MAX_FR_BIT_SIZE MCL_MAX_FP_BIT_SIZE
+#endif
+namespace mcl {
+
+struct CurveParam {
+ /*
+ y^2 = x^3 + b
+ i^2 = -1
+ xi = xi_a + i
+ v^3 = xi
+ w^2 = v
+ */
+ const char *z;
+ int b; // y^2 = x^3 + b
+ int xi_a; // xi = xi_a + i
+ /*
+ BN254, BN381 : Dtype
+ BLS12-381 : Mtype
+ */
+ bool isMtype;
+ int curveType; // same in curve_type.h
+ bool operator==(const CurveParam& rhs) const
+ {
+ return strcmp(z, rhs.z) == 0 && b == rhs.b && xi_a == rhs.xi_a && isMtype == rhs.isMtype;
+ }
+ bool operator!=(const CurveParam& rhs) const { return !operator==(rhs); }
+};
+
+const CurveParam BN254 = { "-0x4080000000000001", 2, 1, false, MCL_BN254 }; // -(2^62 + 2^55 + 1)
+// provisional(experimental) param with maxBitSize = 384
+const CurveParam BN381_1 = { "-0x400011000000000000000001", 2, 1, false, MCL_BN381_1 }; // -(2^94 + 2^76 + 2^72 + 1) // A Family of Implementation-Friendly BN Elliptic Curves
+const CurveParam BN381_2 = { "-0x400040090001000000000001", 2, 1, false, MCL_BN381_2 }; // -(2^94 + 2^78 + 2^67 + 2^64 + 2^48 + 1) // used in relic-toolkit
+const CurveParam BN462 = { "0x4001fffffffffffffffffffffbfff", 5, 2, false, MCL_BN462 }; // 2^114 + 2^101 - 2^14 - 1 // https://eprint.iacr.org/2017/334
+const CurveParam BN_SNARK1 = { "4965661367192848881", 3, 9, false, MCL_BN_SNARK1 };
+const CurveParam BLS12_381 = { "-0xd201000000010000", 4, 1, true, MCL_BLS12_381 };
+const CurveParam BN160 = { "0x4000000031", 3, 4, false, MCL_BN160 };
+
+inline const CurveParam& getCurveParam(int type)
+{
+ switch (type) {
+ case MCL_BN254: return mcl::BN254;
+ case MCL_BN381_1: return mcl::BN381_1;
+ case MCL_BN381_2: return mcl::BN381_2;
+ case MCL_BN462: return mcl::BN462;
+ case MCL_BN_SNARK1: return mcl::BN_SNARK1;
+ case MCL_BLS12_381: return mcl::BLS12_381;
+ case MCL_BN160: return mcl::BN160;
+ default:
+ assert(0);
+ return mcl::BN254;
+ }
+}
+
+namespace bn {
+
+namespace local {
+struct FpTag;
+struct FrTag;
+}
+
+typedef mcl::FpT<local::FpTag, MCL_MAX_FP_BIT_SIZE> Fp;
+typedef mcl::FpT<local::FrTag, MCL_MAX_FR_BIT_SIZE> Fr;
+typedef mcl::Fp2T<Fp> Fp2;
+typedef mcl::Fp6T<Fp> Fp6;
+typedef mcl::Fp12T<Fp> Fp12;
+typedef mcl::EcT<Fp> G1;
+typedef mcl::EcT<Fp2> G2;
+typedef Fp12 GT;
+
+typedef mcl::FpDblT<Fp> FpDbl;
+typedef mcl::Fp2DblT<Fp> Fp2Dbl;
+
+inline void Frobenius(Fp2& y, const Fp2& x)
+{
+ Fp2::Frobenius(y, x);
+}
+inline void Frobenius(Fp12& y, const Fp12& x)
+{
+ Fp12::Frobenius(y, x);
+}
+/*
+ twisted Frobenius for G2
+*/
+void Frobenius(G2& D, const G2& S);
+void Frobenius2(G2& D, const G2& S);
+void Frobenius3(G2& D, const G2& S);
+
+namespace local {
+
+typedef mcl::FixedArray<int8_t, 128> SignVec;
+
+inline size_t getPrecomputeQcoeffSize(const SignVec& sv)
+{
+ size_t idx = 2 + 2;
+ for (size_t i = 2; i < sv.size(); i++) {
+ idx++;
+ if (sv[i]) idx++;
+ }
+ return idx;
+}
+
+template<class X, class C, size_t N>
+X evalPoly(const X& x, const C (&c)[N])
+{
+ X ret = c[N - 1];
+ for (size_t i = 1; i < N; i++) {
+ ret *= x;
+ ret += c[N - 1 - i];
+ }
+ return ret;
+}
+
+enum TwistBtype {
+ tb_generic,
+ tb_1m1i, // 1 - 1i
+ tb_1m2i // 1 - 2i
+};
+
+/*
+ l = (a, b, c) => (a, b * P.y, c * P.x)
+*/
+inline void updateLine(Fp6& l, const G1& P)
+{
+ l.b.a *= P.y;
+ l.b.b *= P.y;
+ l.c.a *= P.x;
+ l.c.b *= P.x;
+}
+
+struct Compress {
+ Fp12& z_;
+ Fp2& g1_;
+ Fp2& g2_;
+ Fp2& g3_;
+ Fp2& g4_;
+ Fp2& g5_;
+ // z is output area
+ Compress(Fp12& z, const Fp12& x)
+ : z_(z)
+ , g1_(z.getFp2()[4])
+ , g2_(z.getFp2()[3])
+ , g3_(z.getFp2()[2])
+ , g4_(z.getFp2()[1])
+ , g5_(z.getFp2()[5])
+ {
+ g2_ = x.getFp2()[3];
+ g3_ = x.getFp2()[2];
+ g4_ = x.getFp2()[1];
+ g5_ = x.getFp2()[5];
+ }
+ Compress(Fp12& z, const Compress& c)
+ : z_(z)
+ , g1_(z.getFp2()[4])
+ , g2_(z.getFp2()[3])
+ , g3_(z.getFp2()[2])
+ , g4_(z.getFp2()[1])
+ , g5_(z.getFp2()[5])
+ {
+ g2_ = c.g2_;
+ g3_ = c.g3_;
+ g4_ = c.g4_;
+ g5_ = c.g5_;
+ }
+ void decompressBeforeInv(Fp2& nume, Fp2& denomi) const
+ {
+ assert(&nume != &denomi);
+
+ if (g2_.isZero()) {
+ Fp2::add(nume, g4_, g4_);
+ nume *= g5_;
+ denomi = g3_;
+ } else {
+ Fp2 t;
+ Fp2::sqr(nume, g5_);
+ Fp2::mul_xi(denomi, nume);
+ Fp2::sqr(nume, g4_);
+ Fp2::sub(t, nume, g3_);
+ t += t;
+ t += nume;
+ Fp2::add(nume, denomi, t);
+ Fp2::divBy4(nume, nume);
+ denomi = g2_;
+ }
+ }
+
+ // output to z
+ void decompressAfterInv()
+ {
+ Fp2& g0 = z_.getFp2()[0];
+ Fp2 t0, t1;
+ // Compute g0.
+ Fp2::sqr(t0, g1_);
+ Fp2::mul(t1, g3_, g4_);
+ t0 -= t1;
+ t0 += t0;
+ t0 -= t1;
+ Fp2::mul(t1, g2_, g5_);
+ t0 += t1;
+ Fp2::mul_xi(g0, t0);
+ g0.a += Fp::one();
+ }
+
+public:
+ void decompress() // for test
+ {
+ Fp2 nume, denomi;
+ decompressBeforeInv(nume, denomi);
+ Fp2::inv(denomi, denomi);
+ g1_ = nume * denomi; // g1 is recoverd.
+ decompressAfterInv();
+ }
+ /*
+ 2275clk * 186 = 423Kclk QQQ
+ */
+ static void squareC(Compress& z)
+ {
+ Fp2 t0, t1, t2;
+ Fp2Dbl T0, T1, T2, T3;
+ Fp2Dbl::sqrPre(T0, z.g4_);
+ Fp2Dbl::sqrPre(T1, z.g5_);
+ Fp2Dbl::mul_xi(T2, T1);
+ T2 += T0;
+ Fp2Dbl::mod(t2, T2);
+ Fp2::add(t0, z.g4_, z.g5_);
+ Fp2Dbl::sqrPre(T2, t0);
+ T0 += T1;
+ T2 -= T0;
+ Fp2Dbl::mod(t0, T2);
+ Fp2::add(t1, z.g2_, z.g3_);
+ Fp2Dbl::sqrPre(T3, t1);
+ Fp2Dbl::sqrPre(T2, z.g2_);
+ Fp2::mul_xi(t1, t0);
+ z.g2_ += t1;
+ z.g2_ += z.g2_;
+ z.g2_ += t1;
+ Fp2::sub(t1, t2, z.g3_);
+ t1 += t1;
+ Fp2Dbl::sqrPre(T1, z.g3_);
+ Fp2::add(z.g3_, t1, t2);
+ Fp2Dbl::mul_xi(T0, T1);
+ T0 += T2;
+ Fp2Dbl::mod(t0, T0);
+ Fp2::sub(z.g4_, t0, z.g4_);
+ z.g4_ += z.g4_;
+ z.g4_ += t0;
+ Fp2Dbl::addPre(T2, T2, T1);
+ T3 -= T2;
+ Fp2Dbl::mod(t0, T3);
+ z.g5_ += t0;
+ z.g5_ += z.g5_;
+ z.g5_ += t0;
+ }
+ static void square_n(Compress& z, int n)
+ {
+ for (int i = 0; i < n; i++) {
+ squareC(z);
+ }
+ }
+ /*
+ Exponentiation over compression for:
+ z = x^Param::z.abs()
+ */
+ static void fixed_power(Fp12& z, const Fp12& x)
+ {
+ if (x.isOne()) {
+ z = 1;
+ return;
+ }
+ Fp12 x_org = x;
+ Fp12 d62;
+ Fp2 c55nume, c55denomi, c62nume, c62denomi;
+ Compress c55(z, x);
+ square_n(c55, 55);
+ c55.decompressBeforeInv(c55nume, c55denomi);
+ Compress c62(d62, c55);
+ square_n(c62, 62 - 55);
+ c62.decompressBeforeInv(c62nume, c62denomi);
+ Fp2 acc;
+ Fp2::mul(acc, c55denomi, c62denomi);
+ Fp2::inv(acc, acc);
+ Fp2 t;
+ Fp2::mul(t, acc, c62denomi);
+ Fp2::mul(c55.g1_, c55nume, t);
+ c55.decompressAfterInv();
+ Fp2::mul(t, acc, c55denomi);
+ Fp2::mul(c62.g1_, c62nume, t);
+ c62.decompressAfterInv();
+ z *= x_org;
+ z *= d62;
+ }
+};
+
+struct MapTo {
+ enum {
+ BNtype,
+ BLS12type,
+ STD_ECtype
+ };
+ Fp c1_; // sqrt(-3)
+ Fp c2_; // (-1 + sqrt(-3)) / 2
+ mpz_class z_;
+ mpz_class cofactor_;
+ int type_;
+ bool useNaiveMapTo_;
+
+ int legendre(bool *pb, const Fp& x) const
+ {
+ mpz_class xx;
+ x.getMpz(pb, xx);
+ if (!*pb) return 0;
+ return gmp::legendre(xx, Fp::getOp().mp);
+ }
+ int legendre(bool *pb, const Fp2& x) const
+ {
+ Fp y;
+ Fp2::norm(y, x);
+ return legendre(pb, y);
+ }
+ void mulFp(Fp& x, const Fp& y) const
+ {
+ x *= y;
+ }
+ void mulFp(Fp2& x, const Fp& y) const
+ {
+ x.a *= y;
+ x.b *= y;
+ }
+ /*
+ P.-A. Fouque and M. Tibouchi,
+ "Indifferentiable hashing to Barreto Naehrig curves,"
+ in Proc. Int. Conf. Cryptol. Inform. Security Latin Amer., 2012, vol. 7533, pp.1-17.
+
+ w = sqrt(-3) t / (1 + b + t^2)
+ Remark: throw exception if t = 0, c1, -c1 and b = 2
+ */
+ template<class G, class F>
+ bool calcBN(G& P, const F& t) const
+ {
+ F x, y, w;
+ bool b;
+ bool negative = legendre(&b, t) < 0;
+ if (!b) return false;
+ if (t.isZero()) return false;
+ F::sqr(w, t);
+ w += G::b_;
+ *w.getFp0() += Fp::one();
+ if (w.isZero()) return false;
+ F::inv(w, w);
+ mulFp(w, c1_);
+ w *= t;
+ for (int i = 0; i < 3; i++) {
+ switch (i) {
+ case 0: F::mul(x, t, w); F::neg(x, x); *x.getFp0() += c2_; break;
+ case 1: F::neg(x, x); *x.getFp0() -= Fp::one(); break;
+ case 2: F::sqr(x, w); F::inv(x, x); *x.getFp0() += Fp::one(); break;
+ }
+ G::getWeierstrass(y, x);
+ if (F::squareRoot(y, y)) {
+ if (negative) F::neg(y, y);
+ P.set(&b, x, y, false);
+ assert(b);
+ return true;
+ }
+ }
+ return false;
+ }
+ /*
+ Faster Hashing to G2
+ Laura Fuentes-Castaneda, Edward Knapp, Francisco Rodriguez-Henriquez
+ section 6.1
+ for BN
+ Q = zP + Frob(3zP) + Frob^2(zP) + Frob^3(P)
+ = -(18x^3 + 12x^2 + 3x + 1)cofactor_ P
+ */
+ void mulByCofactorBN(G2& Q, const G2& P) const
+ {
+#if 0
+ G2::mulGeneric(Q, P, cofactor_);
+#else
+#if 0
+ mpz_class t = -(1 + z_ * (3 + z_ * (12 + z_ * 18)));
+ G2::mulGeneric(Q, P, t * cofactor_);
+#else
+ G2 T0, T1, T2;
+ /*
+ G2::mul (GLV method) can't be used because P is not on G2
+ */
+ G2::mulGeneric(T0, P, z_);
+ G2::dbl(T1, T0);
+ T1 += T0; // 3zP
+ Frobenius(T1, T1);
+ Frobenius2(T2, T0);
+ T0 += T1;
+ T0 += T2;
+ Frobenius3(T2, P);
+ G2::add(Q, T0, T2);
+#endif
+#endif
+ }
+ /*
+ 1.2~1.4 times faster than calBN
+ */
+ template<class G, class F>
+ void naiveMapTo(G& P, const F& t) const
+ {
+ F x = t;
+ for (;;) {
+ F y;
+ G::getWeierstrass(y, x);
+ if (F::squareRoot(y, y)) {
+ bool b;
+ P.set(&b, x, y, false);
+ assert(b);
+ return;
+ }
+ *x.getFp0() += Fp::one();
+ }
+ }
+ /*
+ #(Fp) / r = (z + 1 - t) / r = (z - 1)^2 / 3
+ */
+ void mulByCofactorBLS12(G1& Q, const G1& P) const
+ {
+ G1::mulGeneric(Q, P, cofactor_);
+ }
+ /*
+ Efficient hash maps to G2 on BLS curves
+ Alessandro Budroni, Federico Pintore
+ Q = (z(z-1)-1)P + Frob((z-1)P) + Frob^2(2P)
+ */
+ void mulByCofactorBLS12(G2& Q, const G2& P) const
+ {
+ G2 T0, T1;
+ G2::mulGeneric(T0, P, z_ - 1);
+ G2::mulGeneric(T1, T0, z_);
+ T1 -= P;
+ Frobenius(T0, T0);
+ T0 += T1;
+ G2::dbl(T1, P);
+ Frobenius2(T1, T1);
+ G2::add(Q, T0, T1);
+ }
+ /*
+ cofactor_ is for G2(not used now)
+ */
+ void initBN(const mpz_class& cofactor, const mpz_class &z, int curveType)
+ {
+ z_ = z;
+ cofactor_ = cofactor;
+ if (curveType == MCL_BN254) {
+ const char *c1 = "252364824000000126cd890000000003cf0f0000000000060c00000000000004";
+ const char *c2 = "25236482400000017080eb4000000006181800000000000cd98000000000000b";
+ bool b;
+ c1_.setStr(&b, c1, 16);
+ c2_.setStr(&b, c2, 16);
+ (void)b;
+ return;
+ }
+ bool b = Fp::squareRoot(c1_, -3);
+ assert(b);
+ (void)b;
+ c2_ = (c1_ - 1) / 2;
+ }
+ void initBLS12(const mpz_class& z)
+ {
+ z_ = z;
+ // cofactor for G1
+ cofactor_ = (z - 1) * (z - 1) / 3;
+ bool b = Fp::squareRoot(c1_, -3);
+ assert(b);
+ (void)b;
+ c2_ = (c1_ - 1) / 2;
+ }
+ /*
+ if type == STD_ECtype, then cofactor, z are not used.
+ */
+ void init(const mpz_class& cofactor, const mpz_class &z, int curveType)
+ {
+ if (0 <= curveType && curveType < MCL_EC_BEGIN) {
+ type_ = curveType == MCL_BLS12_381 ? BLS12type : BNtype;
+ } else {
+ type_ = STD_ECtype;
+ }
+ if (type_ == STD_ECtype) {
+ useNaiveMapTo_ = true;
+ } else {
+ useNaiveMapTo_ = false;
+ }
+#ifdef MCL_USE_OLD_MAPTO_FOR_BLS12
+ if (type == BLS12type) useNaiveMapTo_ = true;
+#endif
+ if (type_ == BNtype) {
+ initBN(cofactor, z, curveType);
+ } else if (type_ == BLS12type) {
+ initBLS12(z);
+ }
+ }
+ bool calcG1(G1& P, const Fp& t) const
+ {
+ if (useNaiveMapTo_) {
+ naiveMapTo<G1, Fp>(P, t);
+ } else {
+ if (!calcBN<G1, Fp>(P, t)) return false;
+ }
+ switch (type_) {
+ case BNtype:
+ // no subgroup
+ break;
+ case BLS12type:
+ mulByCofactorBLS12(P, P);
+ break;
+ }
+ assert(P.isValid());
+ return true;
+ }
+ /*
+ get the element in G2 by multiplying the cofactor
+ */
+ bool calcG2(G2& P, const Fp2& t) const
+ {
+ if (useNaiveMapTo_) {
+ naiveMapTo<G2, Fp2>(P, t);
+ } else {
+ if (!calcBN<G2, Fp2>(P, t)) return false;
+ }
+ switch(type_) {
+ case BNtype:
+ mulByCofactorBN(P, P);
+ break;
+ case BLS12type:
+ mulByCofactorBLS12(P, P);
+ break;
+ }
+ assert(P.isValid());
+ return true;
+ }
+};
+
+/*
+ Software implementation of Attribute-Based Encryption: Appendixes
+ GLV for G1 on BN/BLS12
+*/
+struct GLV1 {
+ Fp rw; // rw = 1 / w = (-1 - sqrt(-3)) / 2
+ size_t rBitSize;
+ mpz_class v0, v1;
+ mpz_class B[2][2];
+ mpz_class r;
+private:
+ bool usePrecomputedTable(int curveType)
+ {
+ if (curveType < 0) return false;
+ const struct Tbl {
+ int curveType;
+ const char *rw;
+ size_t rBitSize;
+ const char *v0, *v1;
+ const char *B[2][2];
+ const char *r;
+ } tbl[] = {
+ {
+ MCL_BN254,
+ "49b36240000000024909000000000006cd80000000000007",
+ 256,
+ "2a01fab7e04a017b9c0eb31ff36bf3357",
+ "37937ca688a6b4904",
+ {
+ {
+ "61818000000000028500000000000004",
+ "8100000000000001",
+ },
+ {
+ "8100000000000001",
+ "-61818000000000020400000000000003",
+ },
+ },
+ "2523648240000001ba344d8000000007ff9f800000000010a10000000000000d",
+ },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ if (tbl[i].curveType != curveType) continue;
+ bool b;
+ rw.setStr(&b, tbl[i].rw, 16); if (!b) continue;
+ rBitSize = tbl[i].rBitSize;
+ mcl::gmp::setStr(&b, v0, tbl[i].v0, 16); if (!b) continue;
+ mcl::gmp::setStr(&b, v1, tbl[i].v1, 16); if (!b) continue;
+ mcl::gmp::setStr(&b, B[0][0], tbl[i].B[0][0], 16); if (!b) continue;
+ mcl::gmp::setStr(&b, B[0][1], tbl[i].B[0][1], 16); if (!b) continue;
+ mcl::gmp::setStr(&b, B[1][0], tbl[i].B[1][0], 16); if (!b) continue;
+ mcl::gmp::setStr(&b, B[1][1], tbl[i].B[1][1], 16); if (!b) continue;
+ mcl::gmp::setStr(&b, r, tbl[i].r, 16); if (!b) continue;
+ return true;
+ }
+ return false;
+ }
+public:
+ bool operator==(const GLV1& rhs) const
+ {
+ return rw == rhs.rw && rBitSize == rhs.rBitSize && v0 == rhs.v0 && v1 == rhs.v1
+ && B[0][0] == rhs.B[0][0] && B[0][1] == rhs.B[0][1] && B[1][0] == rhs.B[1][0]
+ && B[1][1] == rhs.B[1][1] && r == rhs.r;
+ }
+ bool operator!=(const GLV1& rhs) const { return !operator==(rhs); }
+#ifndef CYBOZU_DONT_USE_STRING
+ void dump(const mpz_class& x) const
+ {
+ printf("\"%s\",\n", mcl::gmp::getStr(x, 16).c_str());
+ }
+ void dump() const
+ {
+ printf("\"%s\",\n", rw.getStr(16).c_str());
+ printf("%d,\n", (int)rBitSize);
+ dump(v0);
+ dump(v1);
+ dump(B[0][0]); dump(B[0][1]); dump(B[1][0]); dump(B[1][1]);
+ dump(r);
+ }
+#endif
+ void init(const mpz_class& r, const mpz_class& z, bool isBLS12 = false, int curveType = -1)
+ {
+ if (usePrecomputedTable(curveType)) return;
+ bool b = Fp::squareRoot(rw, -3);
+ assert(b);
+ (void)b;
+ rw = -(rw + 1) / 2;
+ this->r = r;
+ rBitSize = gmp::getBitSize(r);
+ rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1);// a little better size
+ if (isBLS12) {
+ /*
+ BLS12
+ L = z^4
+ (-z^2+1) + L = 0
+ 1 + z^2 L = 0
+ */
+ B[0][0] = -z * z + 1;
+ B[0][1] = 1;
+ B[1][0] = 1;
+ B[1][1] = z * z;
+ } else {
+ /*
+ BN
+ L = 36z^4 - 1
+ (6z^2+2z) - (2z+1) L = 0
+ (-2z-1) - (6z^2+4z+1)L = 0
+ */
+ B[0][0] = 6 * z * z + 2 * z;
+ B[0][1] = -2 * z - 1;
+ B[1][0] = -2 * z - 1;
+ B[1][1] = -6 * z * z - 4 * z - 1;
+ }
+ // [v0 v1] = [r 0] * B^(-1)
+ v0 = ((-B[1][1]) << rBitSize) / r;
+ v1 = ((B[1][0]) << rBitSize) / r;
+ }
+ /*
+ L = lambda = p^4
+ L (x, y) = (rw x, y)
+ */
+ void mulLambda(G1& Q, const G1& P) const
+ {
+ Fp::mul(Q.x, P.x, rw);
+ Q.y = P.y;
+ Q.z = P.z;
+ }
+ /*
+ x = a + b * lambda mod r
+ */
+ void split(mpz_class& a, mpz_class& b, const mpz_class& x) const
+ {
+ mpz_class t;
+ t = (x * v0) >> rBitSize;
+ b = (x * v1) >> rBitSize;
+ a = x - (t * B[0][0] + b * B[1][0]);
+ b = - (t * B[0][1] + b * B[1][1]);
+ }
+ void mul(G1& Q, const G1& P, mpz_class x, bool constTime = false) const
+ {
+ typedef mcl::fp::Unit Unit;
+ const size_t maxUnit = 512 / 2 / mcl::fp::UnitBitSize;
+ const int splitN = 2;
+ mpz_class u[splitN];
+ G1 in[splitN];
+ G1 tbl[4];
+ int bitTbl[splitN]; // bit size of u[i]
+ Unit w[splitN][maxUnit]; // unit array of u[i]
+ int maxBit = 0; // max bit of u[i]
+ int maxN = 0;
+ int remainBit = 0;
+
+ x %= r;
+ if (x == 0) {
+ Q.clear();
+ if (constTime) goto DummyLoop;
+ return;
+ }
+ if (x < 0) {
+ x += r;
+ }
+ split(u[0], u[1], x);
+ in[0] = P;
+ mulLambda(in[1], in[0]);
+ for (int i = 0; i < splitN; i++) {
+ if (u[i] < 0) {
+ u[i] = -u[i];
+ G1::neg(in[i], in[i]);
+ }
+ in[i].normalize();
+ }
+#if 0
+ G1::mulGeneric(in[0], in[0], u[0]);
+ G1::mulGeneric(in[1], in[1], u[1]);
+ G1::add(Q, in[0], in[1]);
+ return;
+#else
+ tbl[0] = in[0]; // dummy
+ tbl[1] = in[0];
+ tbl[2] = in[1];
+ G1::add(tbl[3], in[0], in[1]);
+ tbl[3].normalize();
+ for (int i = 0; i < splitN; i++) {
+ bool b;
+ mcl::gmp::getArray(&b, w[i], maxUnit, u[i]);
+ assert(b);
+ bitTbl[i] = (int)mcl::gmp::getBitSize(u[i]);
+ maxBit = fp::max_(maxBit, bitTbl[i]);
+ }
+ assert(maxBit > 0);
+ maxBit--;
+ /*
+ maxBit = maxN * UnitBitSize + remainBit
+ 0 < remainBit <= UnitBitSize
+ */
+ maxN = maxBit / mcl::fp::UnitBitSize;
+ remainBit = maxBit % mcl::fp::UnitBitSize;
+ remainBit++;
+ Q.clear();
+ for (int i = maxN; i >= 0; i--) {
+ for (int j = remainBit - 1; j >= 0; j--) {
+ G1::dbl(Q, Q);
+ uint32_t b0 = (w[0][i] >> j) & 1;
+ uint32_t b1 = (w[1][i] >> j) & 1;
+ uint32_t c = b1 * 2 + b0;
+ if (c == 0) {
+ if (constTime) tbl[0] += tbl[1];
+ } else {
+ Q += tbl[c];
+ }
+ }
+ remainBit = (int)mcl::fp::UnitBitSize;
+ }
+#endif
+ DummyLoop:
+ if (!constTime) return;
+ const int limitBit = (int)rBitSize / splitN;
+ G1 D = tbl[0];
+ for (int i = maxBit + 1; i < limitBit; i++) {
+ G1::dbl(D, D);
+ D += tbl[0];
+ }
+ }
+};
+
+/*
+ GLV method for G2 and GT on BN/BLS12
+*/
+struct GLV2 {
+ size_t rBitSize;
+ mpz_class B[4][4];
+ mpz_class r;
+ mpz_class v[4];
+ mpz_class z;
+ mpz_class abs_z;
+ bool isBLS12;
+ GLV2() : rBitSize(0), isBLS12(false) {}
+ void init(const mpz_class& r, const mpz_class& z, bool isBLS12 = false)
+ {
+ this->r = r;
+ this->z = z;
+ this->abs_z = z < 0 ? -z : z;
+ this->isBLS12 = isBLS12;
+ rBitSize = mcl::gmp::getBitSize(r);
+ rBitSize = (rBitSize + mcl::fp::UnitBitSize - 1) & ~(mcl::fp::UnitBitSize - 1);// a little better size
+ mpz_class z2p1 = z * 2 + 1;
+ B[0][0] = z + 1;
+ B[0][1] = z;
+ B[0][2] = z;
+ B[0][3] = -2 * z;
+ B[1][0] = z2p1;
+ B[1][1] = -z;
+ B[1][2] = -(z + 1);
+ B[1][3] = -z;
+ B[2][0] = 2 * z;
+ B[2][1] = z2p1;
+ B[2][2] = z2p1;
+ B[2][3] = z2p1;
+ B[3][0] = z - 1;
+ B[3][1] = 2 * z2p1;
+ B[3][2] = -2 * z + 1;
+ B[3][3] = z - 1;
+ /*
+ v[] = [r 0 0 0] * B^(-1) = [2z^2+3z+1, 12z^3+8z^2+z, 6z^3+4z^2+z, -(2z+1)]
+ */
+ const char *zBN254 = "-4080000000000001";
+ mpz_class t;
+ bool b;
+ mcl::gmp::setStr(&b, t, zBN254, 16);
+ assert(b);
+ (void)b;
+ if (z == t) {
+ static const char *vTblBN254[] = {
+ "e00a8e7f56e007e5b09fe7fdf43ba998",
+ "-152aff56a8054abf9da75db2da3d6885101e5fd3997d41cb1",
+ "-a957fab5402a55fced3aed96d1eb44295f40f136ee84e09b",
+ "-e00a8e7f56e007e929d7b2667ea6f29c",
+ };
+ for (int i = 0; i < 4; i++) {
+ mcl::gmp::setStr(&b, v[i], vTblBN254[i], 16);
+ assert(b);
+ (void)b;
+ }
+ } else {
+ v[0] = ((1 + z * (3 + z * 2)) << rBitSize) / r;
+ v[1] = ((z * (1 + z * (8 + z * 12))) << rBitSize) / r;
+ v[2] = ((z * (1 + z * (4 + z * 6))) << rBitSize) / r;
+ v[3] = -((z * (1 + z * 2)) << rBitSize) / r;
+ }
+ }
+ /*
+ u[] = [x, 0, 0, 0] - v[] * x * B
+ */
+ void split(mpz_class u[4], const mpz_class& x) const
+ {
+ if (isBLS12) {
+ /*
+ Frob(P) = zP
+ x = u[0] + u[1] z + u[2] z^2 + u[3] z^3
+ */
+ bool isNeg = false;
+ mpz_class t = x;
+ if (t < 0) {
+ t = -t;
+ isNeg = true;
+ }
+ for (int i = 0; i < 4; i++) {
+ // t = t / abs_z, u[i] = t % abs_z
+ mcl::gmp::divmod(t, u[i], t, abs_z);
+ if (((z < 0) && (i & 1)) ^ isNeg) {
+ u[i] = -u[i];
+ }
+ }
+ return;
+ }
+ // BN
+ mpz_class t[4];
+ for (int i = 0; i < 4; i++) {
+ t[i] = (x * v[i]) >> rBitSize;
+ }
+ for (int i = 0; i < 4; i++) {
+ u[i] = (i == 0) ? x : 0;
+ for (int j = 0; j < 4; j++) {
+ u[i] -= t[j] * B[j][i];
+ }
+ }
+ }
+ template<class T>
+ void mul(T& Q, const T& P, mpz_class x, bool constTime = false) const
+ {
+#if 0 // #ifndef NDEBUG
+ {
+ T R;
+ T::mulGeneric(R, P, r);
+ assert(R.isZero());
+ }
+#endif
+ typedef mcl::fp::Unit Unit;
+ const size_t maxUnit = 512 / 2 / mcl::fp::UnitBitSize;
+ const int splitN = 4;
+ mpz_class u[splitN];
+ T in[splitN];
+ T tbl[16];
+ int bitTbl[splitN]; // bit size of u[i]
+ Unit w[splitN][maxUnit]; // unit array of u[i]
+ int maxBit = 0; // max bit of u[i]
+ int maxN = 0;
+ int remainBit = 0;
+
+ x %= r;
+ if (x == 0) {
+ Q.clear();
+ if (constTime) goto DummyLoop;
+ return;
+ }
+ if (x < 0) {
+ x += r;
+ }
+ split(u, x);
+ in[0] = P;
+ Frobenius(in[1], in[0]);
+ Frobenius(in[2], in[1]);
+ Frobenius(in[3], in[2]);
+ for (int i = 0; i < splitN; i++) {
+ if (u[i] < 0) {
+ u[i] = -u[i];
+ T::neg(in[i], in[i]);
+ }
+// in[i].normalize(); // slow
+ }
+#if 0
+ for (int i = 0; i < splitN; i++) {
+ T::mulGeneric(in[i], in[i], u[i]);
+ }
+ T::add(Q, in[0], in[1]);
+ Q += in[2];
+ Q += in[3];
+ return;
+#else
+ tbl[0] = in[0];
+ for (size_t i = 1; i < 16; i++) {
+ tbl[i].clear();
+ if (i & 1) {
+ tbl[i] += in[0];
+ }
+ if (i & 2) {
+ tbl[i] += in[1];
+ }
+ if (i & 4) {
+ tbl[i] += in[2];
+ }
+ if (i & 8) {
+ tbl[i] += in[3];
+ }
+// tbl[i].normalize();
+ }
+ for (int i = 0; i < splitN; i++) {
+ bool b;
+ mcl::gmp::getArray(&b, w[i], maxUnit, u[i]);
+ assert(b);
+ bitTbl[i] = (int)mcl::gmp::getBitSize(u[i]);
+ maxBit = fp::max_(maxBit, bitTbl[i]);
+ }
+ maxBit--;
+ /*
+ maxBit = maxN * UnitBitSize + remainBit
+ 0 < remainBit <= UnitBitSize
+ */
+ maxN = maxBit / mcl::fp::UnitBitSize;
+ remainBit = maxBit % mcl::fp::UnitBitSize;
+ remainBit++;
+ Q.clear();
+ for (int i = maxN; i >= 0; i--) {
+ for (int j = remainBit - 1; j >= 0; j--) {
+ T::dbl(Q, Q);
+ uint32_t b0 = (w[0][i] >> j) & 1;
+ uint32_t b1 = (w[1][i] >> j) & 1;
+ uint32_t b2 = (w[2][i] >> j) & 1;
+ uint32_t b3 = (w[3][i] >> j) & 1;
+ uint32_t c = b3 * 8 + b2 * 4 + b1 * 2 + b0;
+ if (c == 0) {
+ if (constTime) tbl[0] += tbl[1];
+ } else {
+ Q += tbl[c];
+ }
+ }
+ remainBit = (int)mcl::fp::UnitBitSize;
+ }
+#endif
+ DummyLoop:
+ if (!constTime) return;
+ const int limitBit = (int)rBitSize / splitN;
+ T D = tbl[0];
+ for (int i = maxBit + 1; i < limitBit; i++) {
+ T::dbl(D, D);
+ D += tbl[0];
+ }
+ }
+ void pow(Fp12& z, const Fp12& x, mpz_class y, bool constTime = false) const
+ {
+ typedef GroupMtoA<Fp12> AG; // as additive group
+ AG& _z = static_cast<AG&>(z);
+ const AG& _x = static_cast<const AG&>(x);
+ mul(_z, _x, y, constTime);
+ }
+};
+
+struct Param {
+ CurveParam cp;
+ mpz_class z;
+ mpz_class abs_z;
+ bool isNegative;
+ bool isBLS12;
+ mpz_class p;
+ mpz_class r;
+ local::MapTo mapTo;
+ local::GLV1 glv1;
+ local::GLV2 glv2;
+ // for G2 Frobenius
+ Fp2 g2;
+ Fp2 g3;
+ /*
+ Dtype twist
+ (x', y') = phi(x, y) = (x/w^2, y/w^3)
+ y^2 = x^3 + b
+ => (y'w^3)^2 = (x'w^2)^3 + b
+ => y'^2 = x'^3 + b / w^6 ; w^6 = xi
+ => y'^2 = x'^3 + twist_b;
+ */
+ Fp2 twist_b;
+ local::TwistBtype twist_b_type;
+/*
+ mpz_class exp_c0;
+ mpz_class exp_c1;
+ mpz_class exp_c2;
+ mpz_class exp_c3;
+*/
+
+ // Loop parameter for the Miller loop part of opt. ate pairing.
+ local::SignVec siTbl;
+ size_t precomputedQcoeffSize;
+ bool useNAF;
+ local::SignVec zReplTbl;
+
+ // for initG1only
+ G1 basePoint;
+
+ void init(bool *pb, const mcl::CurveParam& cp, fp::Mode mode)
+ {
+ this->cp = cp;
+ isBLS12 = cp.curveType == MCL_BLS12_381;
+ gmp::setStr(pb, z, cp.z);
+ if (!*pb) return;
+ isNegative = z < 0;
+ if (isNegative) {
+ abs_z = -z;
+ } else {
+ abs_z = z;
+ }
+ if (isBLS12) {
+ mpz_class z2 = z * z;
+ mpz_class z4 = z2 * z2;
+ r = z4 - z2 + 1;
+ p = z - 1;
+ p = p * p * r / 3 + z;
+ } else {
+ const int pCoff[] = { 1, 6, 24, 36, 36 };
+ const int rCoff[] = { 1, 6, 18, 36, 36 };
+ p = local::evalPoly(z, pCoff);
+ assert((p % 6) == 1);
+ r = local::evalPoly(z, rCoff);
+ }
+ Fr::init(pb, r, mode);
+ if (!*pb) return;
+ Fp::init(pb, cp.xi_a, p, mode);
+ if (!*pb) return;
+ Fp2::init();
+ const Fp2 xi(cp.xi_a, 1);
+ g2 = Fp2::get_gTbl()[0];
+ g3 = Fp2::get_gTbl()[3];
+ if (cp.isMtype) {
+ Fp2::inv(g2, g2);
+ Fp2::inv(g3, g3);
+ }
+ if (cp.isMtype) {
+ twist_b = Fp2(cp.b) * xi;
+ } else {
+ if (cp.b == 2 && cp.xi_a == 1) {
+ twist_b = Fp2(1, -1); // shortcut
+ } else {
+ twist_b = Fp2(cp.b) / xi;
+ }
+ }
+ if (twist_b == Fp2(1, -1)) {
+ twist_b_type = tb_1m1i;
+ } else if (twist_b == Fp2(1, -2)) {
+ twist_b_type = tb_1m2i;
+ } else {
+ twist_b_type = tb_generic;
+ }
+ G1::init(0, cp.b, mcl::ec::Proj);
+ if (isBLS12) {
+ G1::setOrder(r);
+ }
+ G2::init(0, twist_b, mcl::ec::Proj);
+ G2::setOrder(r);
+
+ const mpz_class largest_c = isBLS12 ? abs_z : gmp::abs(z * 6 + 2);
+ useNAF = gmp::getNAF(siTbl, largest_c);
+ precomputedQcoeffSize = local::getPrecomputeQcoeffSize(siTbl);
+ gmp::getNAF(zReplTbl, gmp::abs(z));
+/*
+ if (isBLS12) {
+ mpz_class z2 = z * z;
+ mpz_class z3 = z2 * z;
+ mpz_class z4 = z3 * z;
+ mpz_class z5 = z4 * z;
+ exp_c0 = z5 - 2 * z4 + 2 * z2 - z + 3;
+ exp_c1 = z4 - 2 * z3 + 2 * z - 1;
+ exp_c2 = z3 - 2 * z2 + z;
+ exp_c3 = z2 - 2 * z + 1;
+ } else {
+ exp_c0 = -2 + z * (-18 + z * (-30 - 36 * z));
+ exp_c1 = 1 + z * (-12 + z * (-18 - 36 * z));
+ exp_c2 = 6 * z * z + 1;
+ }
+*/
+ if (isBLS12) {
+ mapTo.init(0, z, cp.curveType);
+ } else {
+ mapTo.init(2 * p - r, z, cp.curveType);
+ }
+ glv1.init(r, z, isBLS12, cp.curveType);
+ glv2.init(r, z, isBLS12);
+ basePoint.clear();
+ *pb = true;
+ }
+ void initG1only(bool *pb, const mcl::EcParam& para)
+ {
+ Fp::init(pb, para.p);
+ if (!*pb) return;
+ Fr::init(pb, para.n);
+ if (!*pb) return;
+ G1::init(pb, para.a, para.b);
+ if (!*pb) return;
+ G1::setOrder(Fr::getOp().mp);
+ mapTo.init(0, 0, para.curveType);
+ Fp x0, y0;
+ x0.setStr(pb, para.gx);
+ if (!*pb) return;
+ y0.setStr(pb, para.gy);
+ basePoint.set(pb, x0, y0);
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ void init(const mcl::CurveParam& cp, fp::Mode mode)
+ {
+ bool b;
+ init(&b, cp, mode);
+ if (!b) throw cybozu::Exception("Param:init");
+ }
+#endif
+};
+
+template<size_t dummyImpl = 0>
+struct StaticVar {
+ static local::Param param;
+};
+
+template<size_t dummyImpl>
+local::Param StaticVar<dummyImpl>::param;
+
+} // mcl::bn::local
+
+namespace BN {
+
+static const local::Param& param = local::StaticVar<>::param;
+
+} // mcl::bn::BN
+
+namespace local {
+
+inline void mulArrayGLV1(G1& z, const G1& x, const mcl::fp::Unit *y, size_t yn, bool isNegative, bool constTime)
+{
+ mpz_class s;
+ bool b;
+ mcl::gmp::setArray(&b, s, y, yn);
+ assert(b);
+ if (isNegative) s = -s;
+ BN::param.glv1.mul(z, x, s, constTime);
+}
+inline void mulArrayGLV2(G2& z, const G2& x, const mcl::fp::Unit *y, size_t yn, bool isNegative, bool constTime)
+{
+ mpz_class s;
+ bool b;
+ mcl::gmp::setArray(&b, s, y, yn);
+ assert(b);
+ if (isNegative) s = -s;
+ BN::param.glv2.mul(z, x, s, constTime);
+}
+inline void powArrayGLV2(Fp12& z, const Fp12& x, const mcl::fp::Unit *y, size_t yn, bool isNegative, bool constTime)
+{
+ mpz_class s;
+ bool b;
+ mcl::gmp::setArray(&b, s, y, yn);
+ assert(b);
+ if (isNegative) s = -s;
+ BN::param.glv2.pow(z, x, s, constTime);
+}
+
+/*
+ Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions
+ Robert Granger, Michael Scott
+*/
+inline void sqrFp4(Fp2& z0, Fp2& z1, const Fp2& x0, const Fp2& x1)
+{
+#if 1
+ Fp2Dbl T0, T1, T2;
+ Fp2Dbl::sqrPre(T0, x0);
+ Fp2Dbl::sqrPre(T1, x1);
+ Fp2Dbl::mul_xi(T2, T1);
+ Fp2Dbl::add(T2, T2, T0);
+ Fp2::add(z1, x0, x1);
+ Fp2Dbl::mod(z0, T2);
+ Fp2Dbl::sqrPre(T2, z1);
+ Fp2Dbl::sub(T2, T2, T0);
+ Fp2Dbl::sub(T2, T2, T1);
+ Fp2Dbl::mod(z1, T2);
+#else
+ Fp2 t0, t1, t2;
+ Fp2::sqr(t0, x0);
+ Fp2::sqr(t1, x1);
+ Fp2::mul_xi(z0, t1);
+ z0 += t0;
+ Fp2::add(z1, x0, x1);
+ Fp2::sqr(z1, z1);
+ z1 -= t0;
+ z1 -= t1;
+#endif
+}
+
+inline void fasterSqr(Fp12& y, const Fp12& x)
+{
+#if 0
+ Fp12::sqr(y, x);
+#else
+ const Fp2& x0(x.a.a);
+ const Fp2& x4(x.a.b);
+ const Fp2& x3(x.a.c);
+ const Fp2& x2(x.b.a);
+ const Fp2& x1(x.b.b);
+ const Fp2& x5(x.b.c);
+ Fp2& y0(y.a.a);
+ Fp2& y4(y.a.b);
+ Fp2& y3(y.a.c);
+ Fp2& y2(y.b.a);
+ Fp2& y1(y.b.b);
+ Fp2& y5(y.b.c);
+ Fp2 t0, t1;
+ sqrFp4(t0, t1, x0, x1);
+ Fp2::sub(y0, t0, x0);
+ y0 += y0;
+ y0 += t0;
+ Fp2::add(y1, t1, x1);
+ y1 += y1;
+ y1 += t1;
+ Fp2 t2, t3;
+ sqrFp4(t0, t1, x2, x3);
+ sqrFp4(t2, t3, x4, x5);
+ Fp2::sub(y4, t0, x4);
+ y4 += y4;
+ y4 += t0;
+ Fp2::add(y5, t1, x5);
+ y5 += y5;
+ y5 += t1;
+ Fp2::mul_xi(t0, t3);
+ Fp2::add(y2, t0, x2);
+ y2 += y2;
+ y2 += t0;
+ Fp2::sub(y3, t2, x3);
+ y3 += y3;
+ y3 += t2;
+#endif
+}
+
+/*
+ y = x^z if z > 0
+ = unitaryInv(x^(-z)) if z < 0
+*/
+inline void pow_z(Fp12& y, const Fp12& x)
+{
+#if 1
+ if (BN::param.cp.curveType == MCL_BN254) {
+ Compress::fixed_power(y, x);
+ } else {
+ Fp12 orgX = x;
+ y = x;
+ Fp12 conj;
+ conj.a = x.a;
+ Fp6::neg(conj.b, x.b);
+ for (size_t i = 1; i < BN::param.zReplTbl.size(); i++) {
+ fasterSqr(y, y);
+ if (BN::param.zReplTbl[i] > 0) {
+ y *= orgX;
+ } else if (BN::param.zReplTbl[i] < 0) {
+ y *= conj;
+ }
+ }
+ }
+#else
+ Fp12::pow(y, x, param.abs_z);
+#endif
+ if (BN::param.isNegative) {
+ Fp12::unitaryInv(y, y);
+ }
+}
+inline void mul_twist_b(Fp2& y, const Fp2& x)
+{
+ switch (BN::param.twist_b_type) {
+ case local::tb_1m1i:
+ /*
+ b / xi = 1 - 1i
+ (a + bi)(1 - 1i) = (a + b) + (b - a)i
+ */
+ {
+ Fp t;
+ Fp::add(t, x.a, x.b);
+ Fp::sub(y.b, x.b, x.a);
+ y.a = t;
+ }
+ return;
+ case local::tb_1m2i:
+ /*
+ b / xi = 1 - 2i
+ (a + bi)(1 - 2i) = (a + 2b) + (b - 2a)i
+ */
+ {
+ Fp t;
+ Fp::sub(t, x.b, x.a);
+ t -= x.a;
+ Fp::add(y.a, x.a, x.b);
+ y.a += x.b;
+ y.b = t;
+ }
+ return;
+ case local::tb_generic:
+ Fp2::mul(y, x, BN::param.twist_b);
+ return;
+ }
+}
+
+inline void dblLineWithoutP(Fp6& l, G2& Q)
+{
+ Fp2 t0, t1, t2, t3, t4, t5;
+ Fp2Dbl T0, T1;
+ Fp2::sqr(t0, Q.z);
+ Fp2::mul(t4, Q.x, Q.y);
+ Fp2::sqr(t1, Q.y);
+ Fp2::add(t3, t0, t0);
+ Fp2::divBy2(t4, t4);
+ Fp2::add(t5, t0, t1);
+ t0 += t3;
+ mul_twist_b(t2, t0);
+ Fp2::sqr(t0, Q.x);
+ Fp2::add(t3, t2, t2);
+ t3 += t2;
+ Fp2::sub(Q.x, t1, t3);
+ t3 += t1;
+ Q.x *= t4;
+ Fp2::divBy2(t3, t3);
+ Fp2Dbl::sqrPre(T0, t3);
+ Fp2Dbl::sqrPre(T1, t2);
+ Fp2Dbl::sub(T0, T0, T1);
+ Fp2Dbl::add(T1, T1, T1);
+ Fp2Dbl::sub(T0, T0, T1);
+ Fp2::add(t3, Q.y, Q.z);
+ Fp2Dbl::mod(Q.y, T0);
+ Fp2::sqr(t3, t3);
+ t3 -= t5;
+ Fp2::mul(Q.z, t1, t3);
+ Fp2::sub(l.a, t2, t1);
+ l.c = t0;
+ l.b = t3;
+}
+inline void addLineWithoutP(Fp6& l, G2& R, const G2& Q)
+{
+ Fp2 t1, t2, t3, t4;
+ Fp2Dbl T1, T2;
+ Fp2::mul(t1, R.z, Q.x);
+ Fp2::mul(t2, R.z, Q.y);
+ Fp2::sub(t1, R.x, t1);
+ Fp2::sub(t2, R.y, t2);
+ Fp2::sqr(t3, t1);
+ Fp2::mul(R.x, t3, R.x);
+ Fp2::sqr(t4, t2);
+ t3 *= t1;
+ t4 *= R.z;
+ t4 += t3;
+ t4 -= R.x;
+ t4 -= R.x;
+ R.x -= t4;
+ Fp2Dbl::mulPre(T1, t2, R.x);
+ Fp2Dbl::mulPre(T2, t3, R.y);
+ Fp2Dbl::sub(T2, T1, T2);
+ Fp2Dbl::mod(R.y, T2);
+ Fp2::mul(R.x, t1, t4);
+ Fp2::mul(R.z, t3, R.z);
+ Fp2::neg(l.c, t2);
+ Fp2Dbl::mulPre(T1, t2, Q.x);
+ Fp2Dbl::mulPre(T2, t1, Q.y);
+ Fp2Dbl::sub(T1, T1, T2);
+ l.b = t1;
+ Fp2Dbl::mod(l.a, T1);
+}
+inline void dblLine(Fp6& l, G2& Q, const G1& P)
+{
+ dblLineWithoutP(l, Q);
+ local::updateLine(l, P);
+}
+inline void addLine(Fp6& l, G2& R, const G2& Q, const G1& P)
+{
+ addLineWithoutP(l, R, Q);
+ local::updateLine(l, P);
+}
+inline void mulFp6cb_by_G1xy(Fp6& y, const Fp6& x, const G1& P)
+{
+ assert(P.isNormalized());
+ if (&y != &x) y.a = x.a;
+ Fp2::mulFp(y.c, x.c, P.x);
+ Fp2::mulFp(y.b, x.b, P.y);
+}
+
+/*
+ x = a + bv + cv^2
+ y = (y0, y4, y2) -> (y0, 0, y2, 0, y4, 0)
+ z = xy = (a + bv + cv^2)(d + ev)
+ = (ad + ce xi) + ((a + b)(d + e) - ad - be)v + (be + cd)v^2
+*/
+inline void Fp6mul_01(Fp6& z, const Fp6& x, const Fp2& d, const Fp2& e)
+{
+ const Fp2& a = x.a;
+ const Fp2& b = x.b;
+ const Fp2& c = x.c;
+ Fp2 t0, t1;
+ Fp2Dbl AD, CE, BE, CD, T;
+ Fp2Dbl::mulPre(AD, a, d);
+ Fp2Dbl::mulPre(CE, c, e);
+ Fp2Dbl::mulPre(BE, b, e);
+ Fp2Dbl::mulPre(CD, c, d);
+ Fp2::add(t0, a, b);
+ Fp2::add(t1, d, e);
+ Fp2Dbl::mulPre(T, t0, t1);
+ T -= AD;
+ T -= BE;
+ Fp2Dbl::mod(z.b, T);
+ Fp2Dbl::mul_xi(CE, CE);
+ AD += CE;
+ Fp2Dbl::mod(z.a, AD);
+ BE += CD;
+ Fp2Dbl::mod(z.c, BE);
+}
+/*
+ input
+ z = (z0 + z1v + z2v^2) + (z3 + z4v + z5v^2)w = Z0 + Z1w
+ 0 3 4
+ x = (a, b, c) -> (b, 0, 0, c, a, 0) = X0 + X1w
+ X0 = b = (b, 0, 0)
+ X1 = c + av = (c, a, 0)
+ w^2 = v, v^3 = xi
+ output
+ z <- zx = (Z0X0 + Z1X1v) + ((Z0 + Z1)(X0 + X1) - Z0X0 - Z1X1)w
+ Z0X0 = Z0 b
+ Z1X1 = Z1 (c, a, 0)
+ (Z0 + Z1)(X0 + X1) = (Z0 + Z1) (b + c, a, 0)
+*/
+inline void mul_403(Fp12& z, const Fp6& x)
+{
+ const Fp2& a = x.a;
+ const Fp2& b = x.b;
+ const Fp2& c = x.c;
+#if 1
+ Fp6& z0 = z.a;
+ Fp6& z1 = z.b;
+ Fp6 z0x0, z1x1, t0;
+ Fp2 t1;
+ Fp2::add(t1, x.b, c);
+ Fp6::add(t0, z0, z1);
+ Fp2::mul(z0x0.a, z0.a, b);
+ Fp2::mul(z0x0.b, z0.b, b);
+ Fp2::mul(z0x0.c, z0.c, b);
+ Fp6mul_01(z1x1, z1, c, a);
+ Fp6mul_01(t0, t0, t1, a);
+ Fp6::sub(z.b, t0, z0x0);
+ z.b -= z1x1;
+ // a + bv + cv^2 = cxi + av + bv^2
+ Fp2::mul_xi(z1x1.c, z1x1.c);
+ Fp2::add(z.a.a, z0x0.a, z1x1.c);
+ Fp2::add(z.a.b, z0x0.b, z1x1.a);
+ Fp2::add(z.a.c, z0x0.c, z1x1.b);
+#else
+ Fp2& z0 = z.a.a;
+ Fp2& z1 = z.a.b;
+ Fp2& z2 = z.a.c;
+ Fp2& z3 = z.b.a;
+ Fp2& z4 = z.b.b;
+ Fp2& z5 = z.b.c;
+ Fp2Dbl Z0B, Z1B, Z2B, Z3C, Z4C, Z5C;
+ Fp2Dbl T0, T1, T2, T3, T4, T5;
+ Fp2 bc, t;
+ Fp2::addPre(bc, b, c);
+ Fp2::addPre(t, z5, z2);
+ Fp2Dbl::mulPre(T5, t, bc);
+ Fp2Dbl::mulPre(Z5C, z5, c);
+ Fp2Dbl::mulPre(Z2B, z2, b);
+ Fp2Dbl::sub(T5, T5, Z5C);
+ Fp2Dbl::sub(T5, T5, Z2B);
+ Fp2Dbl::mulPre(T0, z1, a);
+ T5 += T0;
+
+ Fp2::addPre(t, z4, z1);
+ Fp2Dbl::mulPre(T4, t, bc);
+ Fp2Dbl::mulPre(Z4C, z4, c);
+ Fp2Dbl::mulPre(Z1B, z1, b);
+ Fp2Dbl::sub(T4, T4, Z4C);
+ Fp2Dbl::sub(T4, T4, Z1B);
+ Fp2Dbl::mulPre(T0, z0, a);
+ T4 += T0;
+
+ Fp2::addPre(t, z3, z0);
+ Fp2Dbl::mulPre(T3, t, bc);
+ Fp2Dbl::mulPre(Z3C, z3, c);
+ Fp2Dbl::mulPre(Z0B, z0, b);
+ Fp2Dbl::sub(T3, T3, Z3C);
+ Fp2Dbl::sub(T3, T3, Z0B);
+ Fp2::mul_xi(t, z2);
+ Fp2Dbl::mulPre(T0, t, a);
+ T3 += T0;
+
+ Fp2Dbl::mulPre(T2, z3, a);
+ T2 += Z2B;
+ T2 += Z4C;
+
+ Fp2::mul_xi(t, z5);
+ Fp2Dbl::mulPre(T1, t, a);
+ T1 += Z1B;
+ T1 += Z3C;
+
+ Fp2Dbl::mulPre(T0, z4, a);
+ T0 += Z5C;
+ Fp2Dbl::mul_xi(T0, T0);
+ T0 += Z0B;
+
+ Fp2Dbl::mod(z0, T0);
+ Fp2Dbl::mod(z1, T1);
+ Fp2Dbl::mod(z2, T2);
+ Fp2Dbl::mod(z3, T3);
+ Fp2Dbl::mod(z4, T4);
+ Fp2Dbl::mod(z5, T5);
+#endif
+}
+/*
+ input
+ z = (z0 + z1v + z2v^2) + (z3 + z4v + z5v^2)w = Z0 + Z1w
+ 0 1 4
+ x = (a, b, c) -> (a, c, 0, 0, b, 0) = X0 + X1w
+ X0 = (a, c, 0)
+ X1 = (0, b, 0)
+ w^2 = v, v^3 = xi
+ output
+ z <- zx = (Z0X0 + Z1X1v) + ((Z0 + Z1)(X0 + X1) - Z0X0 - Z1X1)w
+ Z0X0 = Z0 (a, c, 0)
+ Z1X1 = Z1 (0, b, 0) = Z1 bv
+ (Z0 + Z1)(X0 + X1) = (Z0 + Z1) (a, b + c, 0)
+
+ (a + bv + cv^2)v = c xi + av + bv^2
+*/
+inline void mul_041(Fp12& z, const Fp6& x)
+{
+ const Fp2& a = x.a;
+ const Fp2& b = x.b;
+ const Fp2& c = x.c;
+ Fp6& z0 = z.a;
+ Fp6& z1 = z.b;
+ Fp6 z0x0, z1x1, t0;
+ Fp2 t1;
+ Fp2::mul(z1x1.a, z1.c, b);
+ Fp2::mul_xi(z1x1.a, z1x1.a);
+ Fp2::mul(z1x1.b, z1.a, b);
+ Fp2::mul(z1x1.c, z1.b, b);
+ Fp2::add(t1, x.b, c);
+ Fp6::add(t0, z0, z1);
+ Fp6mul_01(z0x0, z0, a, c);
+ Fp6mul_01(t0, t0, a, t1);
+ Fp6::sub(z.b, t0, z0x0);
+ z.b -= z1x1;
+ // a + bv + cv^2 = cxi + av + bv^2
+ Fp2::mul_xi(z1x1.c, z1x1.c);
+ Fp2::add(z.a.a, z0x0.a, z1x1.c);
+ Fp2::add(z.a.b, z0x0.b, z1x1.a);
+ Fp2::add(z.a.c, z0x0.c, z1x1.b);
+}
+inline void mulSparse(Fp12& z, const Fp6& x)
+{
+ if (BN::param.cp.isMtype) {
+ mul_041(z, x);
+ } else {
+ mul_403(z, x);
+ }
+}
+inline void convertFp6toFp12(Fp12& y, const Fp6& x)
+{
+ if (BN::param.cp.isMtype) {
+ // (a, b, c) -> (a, c, 0, 0, b, 0)
+ y.a.a = x.a;
+ y.b.b = x.b;
+ y.a.b = x.c;
+ y.a.c.clear();
+ y.b.a.clear();
+ y.b.c.clear();
+ } else {
+ // (a, b, c) -> (b, 0, 0, c, a, 0)
+ y.b.b = x.a;
+ y.a.a = x.b;
+ y.b.a = x.c;
+ y.a.b.clear();
+ y.a.c.clear();
+ y.b.c.clear();
+ }
+}
+inline void mulSparse2(Fp12& z, const Fp6& x, const Fp6& y)
+{
+ convertFp6toFp12(z, x);
+ mulSparse(z, y);
+}
+inline void mapToCyclotomic(Fp12& y, const Fp12& x)
+{
+ Fp12 z;
+ Fp12::Frobenius2(z, x); // z = x^(p^2)
+ z *= x; // x^(p^2 + 1)
+ Fp12::inv(y, z);
+ Fp6::neg(z.b, z.b); // z^(p^6) = conjugate of z
+ y *= z;
+}
+/*
+ Implementing Pairings at the 192-bit Security Level
+ D.F.Aranha, L.F.Castaneda, E.Knapp, A.Menezes, F.R.Henriquez
+ Section 4
+*/
+inline void expHardPartBLS12(Fp12& y, const Fp12& x)
+{
+#if 0
+ const mpz_class& p = param.p;
+ mpz_class p2 = p * p;
+ mpz_class p4 = p2 * p2;
+ Fp12::pow(y, x, (p4 - p2 + 1) / param.r * 3);
+ return;
+#endif
+#if 1
+ Fp12 a0, a1, a2, a3, a4, a5, a6, a7;
+ Fp12::unitaryInv(a0, x); // a0 = x^-1
+ fasterSqr(a1, a0); // x^-2
+ pow_z(a2, x); // x^z
+ fasterSqr(a3, a2); // x^2z
+ a1 *= a2; // a1 = x^(z-2)
+ pow_z(a7, a1); // a7 = x^(z^2-2z)
+ pow_z(a4, a7); // a4 = x^(z^3-2z^2)
+ pow_z(a5, a4); // a5 = x^(z^4-2z^3)
+ a3 *= a5; // a3 = x^(z^4-2z^3+2z)
+ pow_z(a6, a3); // a6 = x^(z^5-2z^4+2z^2)
+
+ Fp12::unitaryInv(a1, a1); // x^(2-z)
+ a1 *= a6; // x^(z^5-2z^4+2z^2-z+2)
+ a1 *= x; // x^(z^5-2z^4+2z^2-z+3) = x^c0
+ a3 *= a0; // x^(z^4-2z^3-1) = x^c1
+ Fp12::Frobenius(a3, a3); // x^(c1 p)
+ a1 *= a3; // x^(c0 + c1 p)
+ a4 *= a2; // x^(z^3-2z^2+z) = x^c2
+ Fp12::Frobenius2(a4, a4); // x^(c2 p^2)
+ a1 *= a4; // x^(c0 + c1 p + c2 p^2)
+ a7 *= x; // x^(z^2-2z+1) = x^c3
+ Fp12::Frobenius3(y, a7);
+ y *= a1;
+#else
+ Fp12 t1, t2, t3;
+ Fp12::Frobenius(t1, x);
+ Fp12::Frobenius(t2, t1);
+ Fp12::Frobenius(t3, t2);
+ Fp12::pow(t1, t1, param.exp_c1);
+ Fp12::pow(t2, t2, param.exp_c2);
+ Fp12::pow(t3, t3, param.exp_c3);
+ Fp12::pow(y, x, param.exp_c0);
+ y *= t1;
+ y *= t2;
+ y *= t3;
+#endif
+}
+/*
+ Faster Hashing to G2
+ Laura Fuentes-Castaneda, Edward Knapp, Francisco Rodriguez-Henriquez
+ section 4.1
+ y = x^(d 2z(6z^2 + 3z + 1)) where
+ p = p(z) = 36z^4 + 36z^3 + 24z^2 + 6z + 1
+ r = r(z) = 36z^4 + 36z^3 + 18z^2 + 6z + 1
+ d = (p^4 - p^2 + 1) / r
+ d1 = d 2z(6z^2 + 3z + 1)
+ = c0 + c1 p + c2 p^2 + c3 p^3
+
+ c0 = 1 + 6z + 12z^2 + 12z^3
+ c1 = 4z + 6z^2 + 12z^3
+ c2 = 6z + 6z^2 + 12z^3
+ c3 = -1 + 4z + 6z^2 + 12z^3
+ x -> x^z -> x^2z -> x^4z -> x^6z -> x^(6z^2) -> x^(12z^2) -> x^(12z^3)
+ a = x^(6z) x^(6z^2) x^(12z^3)
+ b = a / (x^2z)
+ x^d1 = (a x^(6z^2) x) b^p a^(p^2) (b / x)^(p^3)
+*/
+inline void expHardPartBN(Fp12& y, const Fp12& x)
+{
+#if 0
+ const mpz_class& p = param.p;
+ mpz_class p2 = p * p;
+ mpz_class p4 = p2 * p2;
+ Fp12::pow(y, x, (p4 - p2 + 1) / param.r);
+ return;
+#endif
+#if 1
+ Fp12 a, b;
+ Fp12 a2, a3;
+ pow_z(b, x); // x^z
+ fasterSqr(b, b); // x^2z
+ fasterSqr(a, b); // x^4z
+ a *= b; // x^6z
+ pow_z(a2, a); // x^(6z^2)
+ a *= a2;
+ fasterSqr(a3, a2); // x^(12z^2)
+ pow_z(a3, a3); // x^(12z^3)
+ a *= a3;
+ Fp12::unitaryInv(b, b);
+ b *= a;
+ a2 *= a;
+ Fp12::Frobenius2(a, a);
+ a *= a2;
+ a *= x;
+ Fp12::unitaryInv(y, x);
+ y *= b;
+ Fp12::Frobenius(b, b);
+ a *= b;
+ Fp12::Frobenius3(y, y);
+ y *= a;
+#else
+ Fp12 t1, t2, t3;
+ Fp12::Frobenius(t1, x);
+ Fp12::Frobenius(t2, t1);
+ Fp12::Frobenius(t3, t2);
+ Fp12::pow(t1, t1, param.exp_c1);
+ Fp12::pow(t2, t2, param.exp_c2);
+ Fp12::pow(y, x, param.exp_c0);
+ y *= t1;
+ y *= t2;
+ y *= t3;
+#endif
+}
+/*
+ remark : returned value is NOT on a curve
+*/
+inline G1 makeAdjP(const G1& P)
+{
+ G1 adjP;
+ Fp::add(adjP.x, P.x, P.x);
+ adjP.x += P.x;
+ Fp::neg(adjP.y, P.y);
+ adjP.z = 1;
+ return adjP;
+}
+
+} // mcl::bn::local
+
+/*
+ y = x^((p^12 - 1) / r)
+ (p^12 - 1) / r = (p^2 + 1) (p^6 - 1) (p^4 - p^2 + 1)/r
+ (a + bw)^(p^6) = a - bw in Fp12
+ (p^4 - p^2 + 1)/r = c0 + c1 p + c2 p^2 + p^3
+*/
+inline void finalExp(Fp12& y, const Fp12& x)
+{
+#if 1
+ mapToCyclotomic(y, x);
+#else
+ const mpz_class& p = param.p;
+ mpz_class p2 = p * p;
+ mpz_class p4 = p2 * p2;
+ Fp12::pow(y, x, p2 + 1);
+ Fp12::pow(y, y, p4 * p2 - 1);
+#endif
+ if (BN::param.isBLS12) {
+ expHardPartBLS12(y, y);
+ } else {
+ expHardPartBN(y, y);
+ }
+}
+inline void millerLoop(Fp12& f, const G1& P_, const G2& Q_)
+{
+ G1 P(P_);
+ G2 Q(Q_);
+ P.normalize();
+ Q.normalize();
+ if (Q.isZero()) {
+ f = 1;
+ return;
+ }
+ assert(BN::param.siTbl[1] == 1);
+ G2 T = Q;
+ G2 negQ;
+ if (BN::param.useNAF) {
+ G2::neg(negQ, Q);
+ }
+ Fp6 d, e, l;
+ d = e = l = 1;
+ G1 adjP = makeAdjP(P);
+ dblLine(d, T, adjP);
+ addLine(l, T, Q, P);
+ mulSparse2(f, d, l);
+ for (size_t i = 2; i < BN::param.siTbl.size(); i++) {
+ dblLine(l, T, adjP);
+ Fp12::sqr(f, f);
+ mulSparse(f, l);
+ if (BN::param.siTbl[i]) {
+ if (BN::param.siTbl[i] > 0) {
+ addLine(l, T, Q, P);
+ } else {
+ addLine(l, T, negQ, P);
+ }
+ mulSparse(f, l);
+ }
+ }
+ if (BN::param.z < 0) {
+ G2::neg(T, T);
+ Fp6::neg(f.b, f.b);
+ }
+ if (BN::param.isBLS12) return;
+ G2 Q1, Q2;
+ Frobenius(Q1, Q);
+ Frobenius(Q2, Q1);
+ G2::neg(Q2, Q2);
+ addLine(d, T, Q1, P);
+ addLine(e, T, Q2, P);
+ Fp12 ft;
+ mulSparse2(ft, d, e);
+ f *= ft;
+}
+inline void pairing(Fp12& f, const G1& P, const G2& Q)
+{
+ millerLoop(f, P, Q);
+ finalExp(f, f);
+}
+/*
+ allocate param.precomputedQcoeffSize elements of Fp6 for Qcoeff
+*/
+inline void precomputeG2(Fp6 *Qcoeff, const G2& Q_)
+{
+ size_t idx = 0;
+ G2 Q(Q_);
+ Q.normalize();
+ if (Q.isZero()) {
+ for (size_t i = 0; i < BN::param.precomputedQcoeffSize; i++) {
+ Qcoeff[i] = 1;
+ }
+ return;
+ }
+ G2 T = Q;
+ G2 negQ;
+ if (BN::param.useNAF) {
+ G2::neg(negQ, Q);
+ }
+ assert(BN::param.siTbl[1] == 1);
+ dblLineWithoutP(Qcoeff[idx++], T);
+ addLineWithoutP(Qcoeff[idx++], T, Q);
+ for (size_t i = 2; i < BN::param.siTbl.size(); i++) {
+ dblLineWithoutP(Qcoeff[idx++], T);
+ if (BN::param.siTbl[i]) {
+ if (BN::param.siTbl[i] > 0) {
+ addLineWithoutP(Qcoeff[idx++], T, Q);
+ } else {
+ addLineWithoutP(Qcoeff[idx++], T, negQ);
+ }
+ }
+ }
+ if (BN::param.z < 0) {
+ G2::neg(T, T);
+ }
+ if (BN::param.isBLS12) return;
+ G2 Q1, Q2;
+ Frobenius(Q1, Q);
+ Frobenius(Q2, Q1);
+ G2::neg(Q2, Q2);
+ addLineWithoutP(Qcoeff[idx++], T, Q1);
+ addLineWithoutP(Qcoeff[idx++], T, Q2);
+ assert(idx == BN::param.precomputedQcoeffSize);
+}
+/*
+ millerLoop(e, P, Q) is same as the following
+ std::vector<Fp6> Qcoeff;
+ precomputeG2(Qcoeff, Q);
+ precomputedMillerLoop(e, P, Qcoeff);
+*/
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+inline void precomputeG2(std::vector<Fp6>& Qcoeff, const G2& Q)
+{
+ Qcoeff.resize(BN::param.precomputedQcoeffSize);
+ precomputeG2(Qcoeff.data(), Q);
+}
+#endif
+template<class Array>
+void precomputeG2(bool *pb, Array& Qcoeff, const G2& Q)
+{
+ *pb = Qcoeff.resize(BN::param.precomputedQcoeffSize);
+ if (!*pb) return;
+ precomputeG2(Qcoeff.data(), Q);
+}
+
+inline void precomputedMillerLoop(Fp12& f, const G1& P_, const Fp6* Qcoeff)
+{
+ G1 P(P_);
+ P.normalize();
+ G1 adjP = makeAdjP(P);
+ size_t idx = 0;
+ Fp6 d, e, l;
+ mulFp6cb_by_G1xy(d, Qcoeff[idx], adjP);
+ idx++;
+
+ mulFp6cb_by_G1xy(e, Qcoeff[idx], P);
+ idx++;
+ mulSparse2(f, d, e);
+ for (size_t i = 2; i < BN::param.siTbl.size(); i++) {
+ mulFp6cb_by_G1xy(l, Qcoeff[idx], adjP);
+ idx++;
+ Fp12::sqr(f, f);
+ mulSparse(f, l);
+ if (BN::param.siTbl[i]) {
+ mulFp6cb_by_G1xy(l, Qcoeff[idx], P);
+ idx++;
+ mulSparse(f, l);
+ }
+ }
+ if (BN::param.z < 0) {
+ Fp6::neg(f.b, f.b);
+ }
+ if (BN::param.isBLS12) return;
+ mulFp6cb_by_G1xy(d, Qcoeff[idx], P);
+ idx++;
+ mulFp6cb_by_G1xy(e, Qcoeff[idx], P);
+ idx++;
+ Fp12 ft;
+ mulSparse2(ft, d, e);
+ f *= ft;
+}
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+inline void precomputedMillerLoop(Fp12& f, const G1& P, const std::vector<Fp6>& Qcoeff)
+{
+ precomputedMillerLoop(f, P, Qcoeff.data());
+}
+#endif
+/*
+ f = MillerLoop(P1, Q1) x MillerLoop(P2, Q2)
+ Q2coeff : precomputed Q2
+*/
+inline void precomputedMillerLoop2mixed(Fp12& f, const G1& P1_, const G2& Q1_, const G1& P2_, const Fp6* Q2coeff)
+{
+ G1 P1(P1_), P2(P2_);
+ G2 Q1(Q1_);
+ P1.normalize();
+ P2.normalize();
+ Q1.normalize();
+ if (Q1.isZero()) {
+ precomputedMillerLoop(f, P2_, Q2coeff);
+ return;
+ }
+ G2 T = Q1;
+ G2 negQ1;
+ if (BN::param.useNAF) {
+ G2::neg(negQ1, Q1);
+ }
+ G1 adjP1 = makeAdjP(P1);
+ G1 adjP2 = makeAdjP(P2);
+ size_t idx = 0;
+ Fp6 d1, d2, e1, e2, l1, l2;
+ dblLine(d1, T, adjP1);
+ mulFp6cb_by_G1xy(d2, Q2coeff[idx], adjP2);
+ idx++;
+
+ Fp12 f1, f2;
+ e1 = 1;
+ addLine(e1, T, Q1, P1);
+ mulSparse2(f1, d1, e1);
+
+ mulFp6cb_by_G1xy(e2, Q2coeff[idx], P2);
+ mulSparse2(f2, d2, e2);
+ Fp12::mul(f, f1, f2);
+ idx++;
+ for (size_t i = 2; i < BN::param.siTbl.size(); i++) {
+ dblLine(l1, T, adjP1);
+ mulFp6cb_by_G1xy(l2, Q2coeff[idx], adjP2);
+ idx++;
+ Fp12::sqr(f, f);
+ mulSparse2(f1, l1, l2);
+ f *= f1;
+ if (BN::param.siTbl[i]) {
+ if (BN::param.siTbl[i] > 0) {
+ addLine(l1, T, Q1, P1);
+ } else {
+ addLine(l1, T, negQ1, P1);
+ }
+ mulFp6cb_by_G1xy(l2, Q2coeff[idx], P2);
+ idx++;
+ mulSparse2(f1, l1, l2);
+ f *= f1;
+ }
+ }
+ if (BN::param.z < 0) {
+ G2::neg(T, T);
+ Fp6::neg(f.b, f.b);
+ }
+ if (BN::param.isBLS12) return;
+ G2 Q11, Q12;
+ Frobenius(Q11, Q1);
+ Frobenius(Q12, Q11);
+ G2::neg(Q12, Q12);
+ addLine(d1, T, Q11, P1);
+ mulFp6cb_by_G1xy(d2, Q2coeff[idx], P2);
+ idx++;
+ addLine(e1, T, Q12, P1);
+ mulFp6cb_by_G1xy(e2, Q2coeff[idx], P2);
+ idx++;
+ mulSparse2(f1, d1, e1);
+ mulSparse2(f2, d2, e2);
+ f *= f1;
+ f *= f2;
+}
+/*
+ f = MillerLoop(P1, Q1) x MillerLoop(P2, Q2)
+ Q1coeff, Q2coeff : precomputed Q1, Q2
+*/
+inline void precomputedMillerLoop2(Fp12& f, const G1& P1_, const Fp6* Q1coeff, const G1& P2_, const Fp6* Q2coeff)
+{
+ G1 P1(P1_), P2(P2_);
+ P1.normalize();
+ P2.normalize();
+ G1 adjP1 = makeAdjP(P1);
+ G1 adjP2 = makeAdjP(P2);
+ size_t idx = 0;
+ Fp6 d1, d2, e1, e2, l1, l2;
+ mulFp6cb_by_G1xy(d1, Q1coeff[idx], adjP1);
+ mulFp6cb_by_G1xy(d2, Q2coeff[idx], adjP2);
+ idx++;
+
+ Fp12 f1, f2;
+ mulFp6cb_by_G1xy(e1, Q1coeff[idx], P1);
+ mulSparse2(f1, d1, e1);
+
+ mulFp6cb_by_G1xy(e2, Q2coeff[idx], P2);
+ mulSparse2(f2, d2, e2);
+ Fp12::mul(f, f1, f2);
+ idx++;
+ for (size_t i = 2; i < BN::param.siTbl.size(); i++) {
+ mulFp6cb_by_G1xy(l1, Q1coeff[idx], adjP1);
+ mulFp6cb_by_G1xy(l2, Q2coeff[idx], adjP2);
+ idx++;
+ Fp12::sqr(f, f);
+ mulSparse2(f1, l1, l2);
+ f *= f1;
+ if (BN::param.siTbl[i]) {
+ mulFp6cb_by_G1xy(l1, Q1coeff[idx], P1);
+ mulFp6cb_by_G1xy(l2, Q2coeff[idx], P2);
+ idx++;
+ mulSparse2(f1, l1, l2);
+ f *= f1;
+ }
+ }
+ if (BN::param.z < 0) {
+ Fp6::neg(f.b, f.b);
+ }
+ if (BN::param.isBLS12) return;
+ mulFp6cb_by_G1xy(d1, Q1coeff[idx], P1);
+ mulFp6cb_by_G1xy(d2, Q2coeff[idx], P2);
+ idx++;
+ mulFp6cb_by_G1xy(e1, Q1coeff[idx], P1);
+ mulFp6cb_by_G1xy(e2, Q2coeff[idx], P2);
+ idx++;
+ mulSparse2(f1, d1, e1);
+ mulSparse2(f2, d2, e2);
+ f *= f1;
+ f *= f2;
+}
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+inline void precomputedMillerLoop2(Fp12& f, const G1& P1, const std::vector<Fp6>& Q1coeff, const G1& P2, const std::vector<Fp6>& Q2coeff)
+{
+ precomputedMillerLoop2(f, P1, Q1coeff.data(), P2, Q2coeff.data());
+}
+inline void precomputedMillerLoop2mixed(Fp12& f, const G1& P1, const G2& Q1, const G1& P2, const std::vector<Fp6>& Q2coeff)
+{
+ precomputedMillerLoop2mixed(f, P1, Q1, P2, Q2coeff.data());
+}
+#endif
+inline void mapToG1(bool *pb, G1& P, const Fp& x) { *pb = BN::param.mapTo.calcG1(P, x); }
+inline void mapToG2(bool *pb, G2& P, const Fp2& x) { *pb = BN::param.mapTo.calcG2(P, x); }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+inline void mapToG1(G1& P, const Fp& x)
+{
+ bool b;
+ mapToG1(&b, P, x);
+ if (!b) throw cybozu::Exception("mapToG1:bad value") << x;
+}
+inline void mapToG2(G2& P, const Fp2& x)
+{
+ bool b;
+ mapToG2(&b, P, x);
+ if (!b) throw cybozu::Exception("mapToG2:bad value") << x;
+}
+#endif
+inline void hashAndMapToG1(G1& P, const void *buf, size_t bufSize)
+{
+ Fp t;
+ t.setHashOf(buf, bufSize);
+ bool b;
+ mapToG1(&b, P, t);
+ // It will not happen that the hashed value is equal to special value
+ assert(b);
+ (void)b;
+}
+inline void hashAndMapToG2(G2& P, const void *buf, size_t bufSize)
+{
+ Fp2 t;
+ t.a.setHashOf(buf, bufSize);
+ t.b.clear();
+ bool b;
+ mapToG2(&b, P, t);
+ // It will not happen that the hashed value is equal to special value
+ assert(b);
+ (void)b;
+}
+#ifndef CYBOZU_DONT_USE_STRING
+inline void hashAndMapToG1(G1& P, const std::string& str)
+{
+ hashAndMapToG1(P, str.c_str(), str.size());
+}
+inline void hashAndMapToG2(G2& P, const std::string& str)
+{
+ hashAndMapToG2(P, str.c_str(), str.size());
+}
+#endif
+inline void verifyOrderG1(bool doVerify)
+{
+ if (BN::param.isBLS12) {
+ G1::setOrder(doVerify ? BN::param.r : 0);
+ }
+}
+inline void verifyOrderG2(bool doVerify)
+{
+ G2::setOrder(doVerify ? BN::param.r : 0);
+}
+
+// backward compatibility
+using mcl::CurveParam;
+static const CurveParam& CurveFp254BNb = BN254;
+static const CurveParam& CurveFp382_1 = BN381_1;
+static const CurveParam& CurveFp382_2 = BN381_2;
+static const CurveParam& CurveFp462 = BN462;
+static const CurveParam& CurveSNARK1 = BN_SNARK1;
+
+/*
+ FrobeniusOnTwist for Dtype
+ p mod 6 = 1, w^6 = xi
+ Frob(x', y') = phi Frob phi^-1(x', y')
+ = phi Frob (x' w^2, y' w^3)
+ = phi (x'^p w^2p, y'^p w^3p)
+ = (F(x') w^2(p - 1), F(y') w^3(p - 1))
+ = (F(x') g^2, F(y') g^3)
+
+ FrobeniusOnTwist for Dtype
+ use (1/g) instead of g
+*/
+inline void Frobenius(G2& D, const G2& S)
+{
+ Fp2::Frobenius(D.x, S.x);
+ Fp2::Frobenius(D.y, S.y);
+ Fp2::Frobenius(D.z, S.z);
+ D.x *= BN::param.g2;
+ D.y *= BN::param.g3;
+}
+inline void Frobenius2(G2& D, const G2& S)
+{
+ Frobenius(D, S);
+ Frobenius(D, D);
+}
+inline void Frobenius3(G2& D, const G2& S)
+{
+ Frobenius(D, S);
+ Frobenius(D, D);
+ Frobenius(D, D);
+}
+
+namespace BN {
+
+using namespace mcl::bn; // backward compatibility
+
+inline void init(bool *pb, const mcl::CurveParam& cp = mcl::BN254, fp::Mode mode = fp::FP_AUTO)
+{
+ local::StaticVar<>::param.init(pb, cp, mode);
+ if (!*pb) return;
+ G1::setMulArrayGLV(local::mulArrayGLV1);
+ G2::setMulArrayGLV(local::mulArrayGLV2);
+ Fp12::setPowArrayGLV(local::powArrayGLV2);
+ G1::setCompressedExpression();
+ G2::setCompressedExpression();
+ *pb = true;
+}
+
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+inline void init(const mcl::CurveParam& cp = mcl::BN254, fp::Mode mode = fp::FP_AUTO)
+{
+ bool b;
+ init(&b, cp, mode);
+ if (!b) throw cybozu::Exception("BN:init");
+}
+#endif
+
+} // mcl::bn::BN
+
+inline void initPairing(bool *pb, const mcl::CurveParam& cp = mcl::BN254, fp::Mode mode = fp::FP_AUTO)
+{
+ BN::init(pb, cp, mode);
+}
+
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+inline void initPairing(const mcl::CurveParam& cp = mcl::BN254, fp::Mode mode = fp::FP_AUTO)
+{
+ bool b;
+ BN::init(&b, cp, mode);
+ if (!b) throw cybozu::Exception("bn:initPairing");
+}
+#endif
+
+inline void initG1only(bool *pb, const mcl::EcParam& para)
+{
+ local::StaticVar<>::param.initG1only(pb, para);
+ if (!*pb) return;
+ G1::setMulArrayGLV(0);
+ G2::setMulArrayGLV(0);
+ Fp12::setPowArrayGLV(0);
+ G1::setCompressedExpression();
+ G2::setCompressedExpression();
+}
+
+inline const G1& getG1basePoint()
+{
+ return local::StaticVar<>::param.basePoint;
+}
+
+} } // mcl::bn
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/bn256.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn256.hpp
new file mode 100644
index 000000000..7a5da7a05
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn256.hpp
@@ -0,0 +1,15 @@
+#pragma once
+/**
+ @file
+ @brief preset class for 256-bit optimal ate pairing over BN curves
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#define MCL_MAX_FP_BIT_SIZE 256
+#include <mcl/bn.hpp>
+
+namespace mcl { namespace bn256 {
+using namespace mcl::bn;
+} }
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/bn384.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn384.hpp
new file mode 100644
index 000000000..8aa14fe5c
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn384.hpp
@@ -0,0 +1,15 @@
+#pragma once
+/**
+ @file
+ @brief preset class for 384-bit optimal ate pairing over BN curves
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#define MCL_MAX_FP_BIT_SIZE 384
+#include <mcl/bn.hpp>
+// #define MCL_MAX_FR_BIT_SIZE 256 // can set if BLS12_381
+
+namespace mcl { namespace bn384 {
+using namespace mcl::bn;
+} }
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/bn512.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn512.hpp
new file mode 100644
index 000000000..c87ad9035
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/bn512.hpp
@@ -0,0 +1,14 @@
+#pragma once
+/**
+ @file
+ @brief preset class for 512-bit optimal ate pairing over BN curves
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#define MCL_MAX_FP_BIT_SIZE 512
+#include <mcl/bn.hpp>
+
+namespace mcl { namespace bn512 {
+using namespace mcl::bn;
+} }
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/conversion.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/conversion.hpp
new file mode 100644
index 000000000..7a04b7fa2
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/conversion.hpp
@@ -0,0 +1,495 @@
+#pragma once
+#include <cybozu/itoa.hpp>
+#include <cybozu/stream.hpp>
+/**
+ @file
+ @brief convertion bin/dec/hex <=> array
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable : 4127)
+#endif
+
+namespace mcl { namespace fp {
+
+namespace local {
+
+inline bool isSpace(char c)
+{
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+}
+template<class InputStream>
+bool skipSpace(char *c, InputStream& is)
+{
+ for (;;) {
+ if (!cybozu::readChar(c, is)) return false;
+ if (!isSpace(*c)) return true;
+ }
+}
+
+#ifndef CYBOZU_DONT_USE_STRING
+template<class InputStream>
+void loadWord(std::string& s, InputStream& is)
+{
+ s.clear();
+ char c;
+ if (!skipSpace(&c, is)) return;
+ s = c;
+ for (;;) {
+ if (!cybozu::readChar(&c, is)) return;
+ if (isSpace(c)) break;
+ s += c;
+ }
+}
+#endif
+
+template<class InputStream>
+size_t loadWord(char *buf, size_t bufSize, InputStream& is)
+{
+ if (bufSize == 0) return 0;
+ char c;
+ if (!skipSpace(&c, is)) return 0;
+ size_t pos = 0;
+ buf[pos++] = c;
+ for (;;) {
+ if (!cybozu::readChar(&c, is)) break;
+ if (isSpace(c)) break;
+ if (pos == bufSize) return 0;
+ buf[pos++] = c;
+ }
+ return pos;
+}
+
+
+/*
+ q = x[] / x
+ @retval r = x[] % x
+ @note accept q == x
+*/
+inline uint32_t divU32(uint32_t *q, const uint32_t *x, size_t xn, uint32_t y)
+{
+ if (xn == 0) return 0;
+ uint32_t r = 0;
+ for (int i = (int)xn - 1; i >= 0; i--) {
+ uint64_t t = (uint64_t(r) << 32) | x[i];
+ q[i] = uint32_t(t / y);
+ r = uint32_t(t % y);
+ }
+ return r;
+}
+
+/*
+ z[0, xn) = x[0, xn) * y
+ return z[xn]
+ @note accept z == x
+*/
+inline uint32_t mulU32(uint32_t *z, const uint32_t *x, size_t xn, uint32_t y)
+{
+ uint32_t H = 0;
+ for (size_t i = 0; i < xn; i++) {
+ uint32_t t = H;
+ uint64_t v = uint64_t(x[i]) * y;
+ uint32_t L = uint32_t(v);
+ H = uint32_t(v >> 32);
+ z[i] = t + L;
+ if (z[i] < t) {
+ H++;
+ }
+ }
+ return H;
+}
+
+/*
+ x[0, xn) += y
+ return 1 if overflow else 0
+*/
+inline uint32_t addU32(uint32_t *x, size_t xn, uint32_t y)
+{
+ uint32_t t = x[0] + y;
+ x[0] = t;
+ if (t >= y) return 0;
+ for (size_t i = 1; i < xn; i++) {
+ t = x[i] + 1;
+ x[i] = t;
+ if (t != 0) return 0;
+ }
+ return 1;
+}
+
+inline uint32_t decToU32(const char *p, size_t size, bool *pb)
+{
+ assert(0 < size && size <= 9);
+ uint32_t x = 0;
+ for (size_t i = 0; i < size; i++) {
+ char c = p[i];
+ if (c < '0' || c > '9') {
+ *pb = false;
+ return 0;
+ }
+ x = x * 10 + uint32_t(c - '0');
+ }
+ *pb = true;
+ return x;
+}
+
+inline bool hexCharToUint8(uint8_t *v, char _c)
+{
+ uint32_t c = uint8_t(_c); // cast is necessary
+ if (c - '0' <= '9' - '0') {
+ c = c - '0';
+ } else if (c - 'a' <= 'f' - 'a') {
+ c = (c - 'a') + 10;
+ } else if (c - 'A' <= 'F' - 'A') {
+ c = (c - 'A') + 10;
+ } else {
+ return false;
+ }
+ *v = uint8_t(c);
+ return true;
+}
+
+template<class UT>
+bool hexToUint(UT *px, const char *p, size_t size)
+{
+ assert(0 < size && size <= sizeof(UT) * 2);
+ UT x = 0;
+ for (size_t i = 0; i < size; i++) {
+ uint8_t v;
+ if (!hexCharToUint8(&v, p[i])) return false;
+ x = x * 16 + v;
+ }
+ *px = x;
+ return true;
+}
+
+template<class UT>
+bool binToUint(UT *px, const char *p, size_t size)
+{
+ assert(0 < size && size <= sizeof(UT) * 8);
+ UT x = 0;
+ for (size_t i = 0; i < size; i++) {
+ UT c = static_cast<uint8_t>(p[i]);
+ if (c == '0') {
+ x = x * 2;
+ } else if (c == '1') {
+ x = x * 2 + 1;
+ } else {
+ return false;
+ }
+ }
+ *px = x;
+ return true;
+}
+
+inline bool parsePrefix(size_t *readSize, bool *isMinus, int *base, const char *buf, size_t bufSize)
+{
+ if (bufSize == 0) return false;
+ size_t pos = 0;
+ if (*buf == '-') {
+ if (bufSize == 1) return false;
+ *isMinus = true;
+ buf++;
+ pos++;
+ } else {
+ *isMinus = false;
+ }
+ if (buf[0] == '0') {
+ if (bufSize > 1 && buf[1] == 'x') {
+ if (*base == 0 || *base == 16) {
+ *base = 16;
+ pos += 2;
+ } else {
+ return false;
+ }
+ } else if (bufSize > 1 && buf[1] == 'b') {
+ if (*base == 0 || *base == 2) {
+ *base = 2;
+ pos += 2;
+ } else {
+ return false;
+ }
+ }
+ }
+ if (*base == 0) *base = 10;
+ if (pos == bufSize) return false;
+ *readSize = pos;
+ return true;
+}
+
+} // mcl::fp::local
+
+/*
+ convert little endian x[0, xn) to buf
+ return written size if success else 0
+ data is buf[bufSize - retval, bufSize)
+ start "0x" if withPrefix
+*/
+template<class T>
+size_t arrayToHex(char *buf, size_t bufSize, const T *x, size_t n, bool withPrefix = false)
+{
+ size_t fullN = 0;
+ if (n > 1) {
+ size_t pos = n - 1;
+ while (pos > 0) {
+ if (x[pos]) break;
+ pos--;
+ }
+ if (pos > 0) fullN = pos;
+ }
+ const T v = n == 0 ? 0 : x[fullN];
+ const size_t topLen = cybozu::getHexLength(v);
+ const size_t startPos = withPrefix ? 2 : 0;
+ const size_t lenT = sizeof(T) * 2;
+ const size_t totalSize = startPos + fullN * lenT + topLen;
+ if (totalSize > bufSize) return 0;
+ char *const top = buf + bufSize - totalSize;
+ if (withPrefix) {
+ top[0] = '0';
+ top[1] = 'x';
+ }
+ cybozu::itohex(&top[startPos], topLen, v, false);
+ for (size_t i = 0; i < fullN; i++) {
+ cybozu::itohex(&top[startPos + topLen + i * lenT], lenT, x[fullN - 1 - i], false);
+ }
+ return totalSize;
+}
+
+/*
+ convert little endian x[0, xn) to buf
+ return written size if success else 0
+ data is buf[bufSize - retval, bufSize)
+ start "0b" if withPrefix
+*/
+template<class T>
+size_t arrayToBin(char *buf, size_t bufSize, const T *x, size_t n, bool withPrefix)
+{
+ size_t fullN = 0;
+ if (n > 1) {
+ size_t pos = n - 1;
+ while (pos > 0) {
+ if (x[pos]) break;
+ pos--;
+ }
+ if (pos > 0) fullN = pos;
+ }
+ const T v = n == 0 ? 0 : x[fullN];
+ const size_t topLen = cybozu::getBinLength(v);
+ const size_t startPos = withPrefix ? 2 : 0;
+ const size_t lenT = sizeof(T) * 8;
+ const size_t totalSize = startPos + fullN * lenT + topLen;
+ if (totalSize > bufSize) return 0;
+ char *const top = buf + bufSize - totalSize;
+ if (withPrefix) {
+ top[0] = '0';
+ top[1] = 'b';
+ }
+ cybozu::itobin(&top[startPos], topLen, v);
+ for (size_t i = 0; i < fullN; i++) {
+ cybozu::itobin(&top[startPos + topLen + i * lenT], lenT, x[fullN - 1 - i]);
+ }
+ return totalSize;
+}
+
+/*
+ convert hex string to x[0..xn)
+ hex string = [0-9a-fA-F]+
+*/
+template<class UT>
+inline size_t hexToArray(UT *x, size_t maxN, const char *buf, size_t bufSize)
+{
+ if (bufSize == 0) return 0;
+ const size_t unitLen = sizeof(UT) * 2;
+ const size_t q = bufSize / unitLen;
+ const size_t r = bufSize % unitLen;
+ const size_t requireSize = q + (r ? 1 : 0);
+ if (maxN < requireSize) return 0;
+ for (size_t i = 0; i < q; i++) {
+ if (!local::hexToUint(&x[i], &buf[r + (q - 1 - i) * unitLen], unitLen)) return 0;
+ }
+ if (r) {
+ if (!local::hexToUint(&x[q], buf, r)) return 0;
+ }
+ return requireSize;
+}
+/*
+ convert bin string to x[0..xn)
+ bin string = [01]+
+*/
+template<class UT>
+inline size_t binToArray(UT *x, size_t maxN, const char *buf, size_t bufSize)
+{
+ if (bufSize == 0) return 0;
+ const size_t unitLen = sizeof(UT) * 8;
+ const size_t q = bufSize / unitLen;
+ const size_t r = bufSize % unitLen;
+ const size_t requireSize = q + (r ? 1 : 0);
+ if (maxN < requireSize) return 0;
+ for (size_t i = 0; i < q; i++) {
+ if (!local::binToUint(&x[i], &buf[r + (q - 1 - i) * unitLen], unitLen)) return 0;
+ }
+ if (r) {
+ if (!local::binToUint(&x[q], buf, r)) return 0;
+ }
+ return requireSize;
+}
+
+/*
+ little endian x[0, xn) to buf
+ return written size if success else 0
+ data is buf[bufSize - retval, bufSize)
+*/
+template<class UT>
+inline size_t arrayToDec(char *buf, size_t bufSize, const UT *x, size_t xn)
+{
+ const size_t maxN = 64;
+ uint32_t t[maxN];
+ if (sizeof(UT) == 8) {
+ xn *= 2;
+ }
+ if (xn > maxN) return 0;
+ memcpy(t, x, xn * sizeof(t[0]));
+
+ const size_t width = 9;
+ const uint32_t i1e9 = 1000000000U;
+ size_t pos = 0;
+ for (;;) {
+ uint32_t r = local::divU32(t, t, xn, i1e9);
+ while (xn > 0 && t[xn - 1] == 0) xn--;
+ size_t len = cybozu::itoa_local::uintToDec(buf, bufSize - pos, r);
+ if (len == 0) return 0;
+ assert(0 < len && len <= width);
+ if (xn == 0) return pos + len;
+ // fill (width - len) '0'
+ for (size_t j = 0; j < width - len; j++) {
+ buf[bufSize - pos - width + j] = '0';
+ }
+ pos += width;
+ }
+}
+
+/*
+ convert buf[0, bufSize) to x[0, num)
+ return written num if success else 0
+*/
+template<class UT>
+inline size_t decToArray(UT *_x, size_t maxN, const char *buf, size_t bufSize)
+{
+ assert(sizeof(UT) == 4 || sizeof(UT) == 8);
+ const size_t width = 9;
+ const uint32_t i1e9 = 1000000000U;
+ if (maxN == 0) return 0;
+ if (sizeof(UT) == 8) {
+ maxN *= 2;
+ }
+ uint32_t *x = reinterpret_cast<uint32_t*>(_x);
+ size_t xn = 1;
+ x[0] = 0;
+ while (bufSize > 0) {
+ size_t n = bufSize % width;
+ if (n == 0) n = width;
+ bool b;
+ uint32_t v = local::decToU32(buf, n, &b);
+ if (!b) return 0;
+ uint32_t H = local::mulU32(x, x, xn, i1e9);
+ if (H > 0) {
+ if (xn == maxN) return 0;
+ x[xn++] = H;
+ }
+ H = local::addU32(x, xn, v);
+ if (H > 0) {
+ if (xn == maxN) return 0;
+ x[xn++] = H;
+ }
+ buf += n;
+ bufSize -= n;
+ }
+ if (sizeof(UT) == 8 && (xn & 1)) {
+ x[xn++] = 0;
+ }
+ return xn / (sizeof(UT) / 4);
+}
+
+/*
+ return retavl is written size if success else 0
+ REMARK : the top of string is buf + bufSize - retval
+*/
+template<class UT>
+size_t arrayToStr(char *buf, size_t bufSize, const UT *x, size_t n, int base, bool withPrefix)
+{
+ switch (base) {
+ case 0:
+ case 10:
+ return arrayToDec(buf, bufSize, x, n);
+ case 16:
+ return arrayToHex(buf, bufSize, x, n, withPrefix);
+ case 2:
+ return arrayToBin(buf, bufSize, x, n, withPrefix);
+ default:
+ return 0;
+ }
+}
+
+template<class UT>
+size_t strToArray(bool *pIsMinus, UT *x, size_t xN, const char *buf, size_t bufSize, int ioMode)
+{
+ ioMode &= 31;
+ size_t readSize;
+ if (!local::parsePrefix(&readSize, pIsMinus, &ioMode, buf, bufSize)) return 0;
+ switch (ioMode) {
+ case 10:
+ return decToArray(x, xN, buf + readSize, bufSize - readSize);
+ case 16:
+ return hexToArray(x, xN, buf + readSize, bufSize - readSize);
+ case 2:
+ return binToArray(x, xN, buf + readSize, bufSize - readSize);
+ default:
+ return 0;
+ }
+}
+
+/*
+ convert src[0, n) to (n * 2) byte hex string and write it to os
+ return true if success else flase
+*/
+template<class OutputStream>
+void writeHexStr(bool *pb, OutputStream& os, const void *src, size_t n)
+{
+ const uint8_t *p = (const uint8_t *)src;
+ for (size_t i = 0; i < n; i++) {
+ char hex[2];
+ cybozu::itohex(hex, sizeof(hex), p[i], false);
+ cybozu::write(pb, os, hex, sizeof(hex));
+ if (!*pb) return;
+ }
+ *pb = true;
+}
+/*
+ read hex string from is and convert it to byte array
+ return written buffer size
+*/
+template<class InputStream>
+inline size_t readHexStr(void *buf, size_t n, InputStream& is)
+{
+ bool b;
+ uint8_t *dst = (uint8_t *)buf;
+ for (size_t i = 0; i < n; i++) {
+ uint8_t L, H;
+ char c[2];
+ if (cybozu::readSome(c, sizeof(c), is) != sizeof(c)) return i;
+ b = local::hexCharToUint8(&H, c[0]);
+ if (!b) return i;
+ b = local::hexCharToUint8(&L, c[1]);
+ if (!b) return i;
+ dst[i] = (H << 4) | L;
+ }
+ return n;
+}
+
+} } // mcl::fp
+
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/curve_type.h b/vendor/github.com/byzantine-lab/mcl/include/mcl/curve_type.h
new file mode 100644
index 000000000..9e4a941a0
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/curve_type.h
@@ -0,0 +1,35 @@
+#pragma once
+/**
+ @file
+ @brief curve type
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+
+enum {
+ MCL_BN254 = 0,
+ MCL_BN381_1 = 1,
+ MCL_BN381_2 = 2,
+ MCL_BN462 = 3,
+ MCL_BN_SNARK1 = 4,
+ MCL_BLS12_381 = 5,
+ MCL_BN160 = 6,
+
+ /*
+ for only G1
+ the size of curve must be less or equal to MCLBN_FP_UNIT_SIZE
+ */
+ MCL_EC_BEGIN = 100,
+ MCL_SECP192K1 = MCL_EC_BEGIN,
+ MCL_SECP224K1 = 101,
+ MCL_SECP256K1 = 102,
+ MCL_SECP384R1 = 103,
+ MCL_SECP521R1 = 104,
+ MCL_NIST_P192 = 105,
+ MCL_NIST_P224 = 106,
+ MCL_NIST_P256 = 107,
+ MCL_EC_END = MCL_NIST_P256 + 1,
+ MCL_NIST_P384 = MCL_SECP384R1,
+ MCL_NIST_P521 = MCL_SECP521R1
+};
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/ec.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/ec.hpp
new file mode 100644
index 000000000..b8eb10be3
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/ec.hpp
@@ -0,0 +1,1045 @@
+#pragma once
+/**
+ @file
+ @brief elliptic curve
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <stdlib.h>
+#include <cybozu/exception.hpp>
+#include <mcl/op.hpp>
+#include <mcl/util.hpp>
+
+//#define MCL_EC_USE_AFFINE
+
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable : 4458)
+#endif
+
+namespace mcl {
+
+namespace ec {
+
+enum Mode {
+ Jacobi = 0,
+ Proj = 1
+};
+
+} // mcl::ec
+
+/*
+ elliptic curve
+ y^2 = x^3 + ax + b (affine)
+ y^2 = x^3 + az^4 + bz^6 (Jacobi) x = X/Z^2, y = Y/Z^3
+*/
+template<class _Fp>
+class EcT : public fp::Serializable<EcT<_Fp> > {
+ enum {
+ zero,
+ minus3,
+ generic
+ };
+public:
+ typedef _Fp Fp;
+ typedef _Fp BaseFp;
+#ifdef MCL_EC_USE_AFFINE
+ Fp x, y;
+ bool inf_;
+#else
+ Fp x, y, z;
+ static int mode_;
+#endif
+ static Fp a_;
+ static Fp b_;
+ static int specialA_;
+ static int ioMode_;
+ /*
+ order_ is the order of G2 which is the subgroup of EcT<Fp2>.
+ check the order of the elements if verifyOrder_ is true
+ */
+ static bool verifyOrder_;
+ static mpz_class order_;
+ static void (*mulArrayGLV)(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime);
+ /* default constructor is undefined value */
+ EcT() {}
+ EcT(const Fp& _x, const Fp& _y)
+ {
+ set(_x, _y);
+ }
+ bool isNormalized() const
+ {
+#ifdef MCL_EC_USE_AFFINE
+ return true;
+#else
+ return isZero() || z.isOne();
+#endif
+ }
+#ifndef MCL_EC_USE_AFFINE
+private:
+ void normalizeJacobi()
+ {
+ assert(!z.isZero());
+ Fp rz2;
+ Fp::inv(z, z);
+ Fp::sqr(rz2, z);
+ x *= rz2;
+ y *= rz2;
+ y *= z;
+ z = 1;
+ }
+ void normalizeProj()
+ {
+ assert(!z.isZero());
+ Fp::inv(z, z);
+ x *= z;
+ y *= z;
+ z = 1;
+ }
+ // Y^2 == X(X^2 + aZ^4) + bZ^6
+ bool isValidJacobi() const
+ {
+ Fp y2, x2, z2, z4, t;
+ Fp::sqr(x2, x);
+ Fp::sqr(y2, y);
+ Fp::sqr(z2, z);
+ Fp::sqr(z4, z2);
+ Fp::mul(t, z4, a_);
+ t += x2;
+ t *= x;
+ z4 *= z2;
+ z4 *= b_;
+ t += z4;
+ return y2 == t;
+ }
+ // (Y^2 - bZ^2)Z = X(X^2 + aZ^2)
+ bool isValidProj() const
+ {
+ Fp y2, x2, z2, t;
+ Fp::sqr(x2, x);
+ Fp::sqr(y2, y);
+ Fp::sqr(z2, z);
+ Fp::mul(t, a_, z2);
+ t += x2;
+ t *= x;
+ z2 *= b_;
+ y2 -= z2;
+ y2 *= z;
+ return y2 == t;
+ }
+#endif
+ // y^2 == (x^2 + a)x + b
+ static inline bool isValid(const Fp& _x, const Fp& _y)
+ {
+ Fp y2, t;
+ Fp::sqr(y2, _y);
+ Fp::sqr(t, _x);
+ t += a_;
+ t *= _x;
+ t += b_;
+ return y2 == t;
+ }
+public:
+ void normalize()
+ {
+#ifndef MCL_EC_USE_AFFINE
+ if (isNormalized()) return;
+ switch (mode_) {
+ case ec::Jacobi:
+ normalizeJacobi();
+ break;
+ case ec::Proj:
+ normalizeProj();
+ break;
+ }
+#endif
+ }
+ static void normalize(EcT& y, const EcT& x)
+ {
+ y = x;
+ y.normalize();
+ }
+ static inline void init(const Fp& a, const Fp& b, int mode = ec::Jacobi)
+ {
+ a_ = a;
+ b_ = b;
+ if (a_.isZero()) {
+ specialA_ = zero;
+ } else if (a_ == -3) {
+ specialA_ = minus3;
+ } else {
+ specialA_ = generic;
+ }
+ ioMode_ = 0;
+ verifyOrder_ = false;
+ order_ = 0;
+ mulArrayGLV = 0;
+#ifdef MCL_EC_USE_AFFINE
+ cybozu::disable_warning_unused_variable(mode);
+#else
+ assert(mode == ec::Jacobi || mode == ec::Proj);
+ mode_ = mode;
+#endif
+ }
+ /*
+ verify the order of *this is equal to order if order != 0
+ in constructor, set, setStr, operator<<().
+ */
+ static void setOrder(const mpz_class& order)
+ {
+ if (order != 0) {
+ verifyOrder_ = true;
+ order_ = order;
+ } else {
+ verifyOrder_ = false;
+ // don't clear order_ because it is used for isValidOrder()
+ }
+ }
+ static void setMulArrayGLV(void f(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime))
+ {
+ mulArrayGLV = f;
+ }
+ static inline void init(bool *pb, const char *astr, const char *bstr, int mode = ec::Jacobi)
+ {
+ Fp a, b;
+ a.setStr(pb, astr);
+ if (!*pb) return;
+ b.setStr(pb, bstr);
+ if (!*pb) return;
+ init(a, b, mode);
+ }
+ // verify the order
+ bool isValidOrder() const
+ {
+ EcT Q;
+ EcT::mulGeneric(Q, *this, order_);
+ return Q.isZero();
+ }
+ bool isValid() const
+ {
+ if (isZero()) return true;
+ bool isOK = false;
+#ifndef MCL_EC_USE_AFFINE
+ if (!z.isOne()) {
+ switch (mode_) {
+ case ec::Jacobi:
+ isOK = isValidJacobi();
+ break;
+ case ec::Proj:
+ isOK = isValidProj();
+ break;
+ }
+ } else
+#endif
+ {
+ isOK = isValid(x, y);
+ }
+ if (!isOK) return false;
+ if (verifyOrder_) return isValidOrder();
+ return true;
+ }
+ void set(bool *pb, const Fp& _x, const Fp& _y, bool verify = true)
+ {
+ if (verify && !isValid(_x, _y)) {
+ *pb = false;
+ return;
+ }
+ x = _x; y = _y;
+#ifdef MCL_EC_USE_AFFINE
+ inf_ = false;
+#else
+ z = 1;
+#endif
+ if (verify && verifyOrder_ && !isValidOrder()) {
+ *pb = false;
+ } else {
+ *pb = true;
+ }
+ }
+ void clear()
+ {
+#ifdef MCL_EC_USE_AFFINE
+ inf_ = true;
+#else
+ z.clear();
+#endif
+ x.clear();
+ y.clear();
+ }
+#ifndef MCL_EC_USE_AFFINE
+ static inline void dblNoVerifyInfJacobi(EcT& R, const EcT& P)
+ {
+ Fp S, M, t, y2;
+ Fp::sqr(y2, P.y);
+ Fp::mul(S, P.x, y2);
+ const bool isPzOne = P.z.isOne();
+ S += S;
+ S += S;
+ Fp::sqr(M, P.x);
+ switch (specialA_) {
+ case zero:
+ Fp::add(t, M, M);
+ M += t;
+ break;
+ case minus3:
+ if (isPzOne) {
+ M -= P.z;
+ } else {
+ Fp::sqr(t, P.z);
+ Fp::sqr(t, t);
+ M -= t;
+ }
+ Fp::add(t, M, M);
+ M += t;
+ break;
+ case generic:
+ default:
+ if (isPzOne) {
+ t = a_;
+ } else {
+ Fp::sqr(t, P.z);
+ Fp::sqr(t, t);
+ t *= a_;
+ }
+ t += M;
+ M += M;
+ M += t;
+ break;
+ }
+ Fp::sqr(R.x, M);
+ R.x -= S;
+ R.x -= S;
+ if (isPzOne) {
+ R.z = P.y;
+ } else {
+ Fp::mul(R.z, P.y, P.z);
+ }
+ R.z += R.z;
+ Fp::sqr(y2, y2);
+ y2 += y2;
+ y2 += y2;
+ y2 += y2;
+ Fp::sub(R.y, S, R.x);
+ R.y *= M;
+ R.y -= y2;
+ }
+ static inline void dblNoVerifyInfProj(EcT& R, const EcT& P)
+ {
+ const bool isPzOne = P.z.isOne();
+ Fp w, t, h;
+ switch (specialA_) {
+ case zero:
+ Fp::sqr(w, P.x);
+ Fp::add(t, w, w);
+ w += t;
+ break;
+ case minus3:
+ Fp::sqr(w, P.x);
+ if (isPzOne) {
+ w -= P.z;
+ } else {
+ Fp::sqr(t, P.z);
+ w -= t;
+ }
+ Fp::add(t, w, w);
+ w += t;
+ break;
+ case generic:
+ default:
+ if (isPzOne) {
+ w = a_;
+ } else {
+ Fp::sqr(w, P.z);
+ w *= a_;
+ }
+ Fp::sqr(t, P.x);
+ w += t;
+ w += t;
+ w += t; // w = a z^2 + 3x^2
+ break;
+ }
+ if (isPzOne) {
+ R.z = P.y;
+ } else {
+ Fp::mul(R.z, P.y, P.z); // s = yz
+ }
+ Fp::mul(t, R.z, P.x);
+ t *= P.y; // xys
+ t += t;
+ t += t; // 4(xys) ; 4B
+ Fp::sqr(h, w);
+ h -= t;
+ h -= t; // w^2 - 8B
+ Fp::mul(R.x, h, R.z);
+ t -= h; // h is free
+ t *= w;
+ Fp::sqr(w, P.y);
+ R.x += R.x;
+ R.z += R.z;
+ Fp::sqr(h, R.z);
+ w *= h;
+ R.z *= h;
+ Fp::sub(R.y, t, w);
+ R.y -= w;
+ }
+#endif
+ static inline void dblNoVerifyInf(EcT& R, const EcT& P)
+ {
+#ifdef MCL_EC_USE_AFFINE
+ Fp t, s;
+ Fp::sqr(t, P.x);
+ Fp::add(s, t, t);
+ t += s;
+ t += a_;
+ Fp::add(s, P.y, P.y);
+ t /= s;
+ Fp::sqr(s, t);
+ s -= P.x;
+ Fp x3;
+ Fp::sub(x3, s, P.x);
+ Fp::sub(s, P.x, x3);
+ s *= t;
+ Fp::sub(R.y, s, P.y);
+ R.x = x3;
+ R.inf_ = false;
+#else
+ switch (mode_) {
+ case ec::Jacobi:
+ dblNoVerifyInfJacobi(R, P);
+ break;
+ case ec::Proj:
+ dblNoVerifyInfProj(R, P);
+ break;
+ }
+#endif
+ }
+ static inline void dbl(EcT& R, const EcT& P)
+ {
+ if (P.isZero()) {
+ R.clear();
+ return;
+ }
+ dblNoVerifyInf(R, P);
+ }
+#ifndef MCL_EC_USE_AFFINE
+ static inline void addJacobi(EcT& R, const EcT& P, const EcT& Q, bool isPzOne, bool isQzOne)
+ {
+ Fp r, U1, S1, H, H3;
+ if (isPzOne) {
+ // r = 1;
+ } else {
+ Fp::sqr(r, P.z);
+ }
+ if (isQzOne) {
+ U1 = P.x;
+ if (isPzOne) {
+ H = Q.x;
+ } else {
+ Fp::mul(H, Q.x, r);
+ }
+ H -= U1;
+ S1 = P.y;
+ } else {
+ Fp::sqr(S1, Q.z);
+ Fp::mul(U1, P.x, S1);
+ if (isPzOne) {
+ H = Q.x;
+ } else {
+ Fp::mul(H, Q.x, r);
+ }
+ H -= U1;
+ S1 *= Q.z;
+ S1 *= P.y;
+ }
+ if (isPzOne) {
+ r = Q.y;
+ } else {
+ r *= P.z;
+ r *= Q.y;
+ }
+ r -= S1;
+ if (H.isZero()) {
+ if (r.isZero()) {
+ dblNoVerifyInf(R, P);
+ } else {
+ R.clear();
+ }
+ return;
+ }
+ if (isPzOne) {
+ R.z = H;
+ } else {
+ Fp::mul(R.z, P.z, H);
+ }
+ if (!isQzOne) {
+ R.z *= Q.z;
+ }
+ Fp::sqr(H3, H); // H^2
+ Fp::sqr(R.y, r); // r^2
+ U1 *= H3; // U1 H^2
+ H3 *= H; // H^3
+ R.y -= U1;
+ R.y -= U1;
+ Fp::sub(R.x, R.y, H3);
+ U1 -= R.x;
+ U1 *= r;
+ H3 *= S1;
+ Fp::sub(R.y, U1, H3);
+ }
+ static inline void addProj(EcT& R, const EcT& P, const EcT& Q, bool isPzOne, bool isQzOne)
+ {
+ Fp r, PyQz, v, A, vv;
+ if (isQzOne) {
+ r = P.x;
+ PyQz = P.y;
+ } else {
+ Fp::mul(r, P.x, Q.z);
+ Fp::mul(PyQz, P.y, Q.z);
+ }
+ if (isPzOne) {
+ A = Q.y;
+ v = Q.x;
+ } else {
+ Fp::mul(A, Q.y, P.z);
+ Fp::mul(v, Q.x, P.z);
+ }
+ v -= r;
+ if (v.isZero()) {
+ if (A == PyQz) {
+ dblNoVerifyInf(R, P);
+ } else {
+ R.clear();
+ }
+ return;
+ }
+ Fp::sub(R.y, A, PyQz);
+ Fp::sqr(A, R.y);
+ Fp::sqr(vv, v);
+ r *= vv;
+ vv *= v;
+ if (isQzOne) {
+ R.z = P.z;
+ } else {
+ if (isPzOne) {
+ R.z = Q.z;
+ } else {
+ Fp::mul(R.z, P.z, Q.z);
+ }
+ }
+ // R.z = 1 if isPzOne && isQzOne
+ if (isPzOne && isQzOne) {
+ R.z = vv;
+ } else {
+ A *= R.z;
+ R.z *= vv;
+ }
+ A -= vv;
+ vv *= PyQz;
+ A -= r;
+ A -= r;
+ Fp::mul(R.x, v, A);
+ r -= A;
+ R.y *= r;
+ R.y -= vv;
+ }
+#endif
+ static inline void add(EcT& R, const EcT& P, const EcT& Q) {
+ if (P.isZero()) { R = Q; return; }
+ if (Q.isZero()) { R = P; return; }
+ if (&P == &Q) {
+ dblNoVerifyInf(R, P);
+ return;
+ }
+#ifdef MCL_EC_USE_AFFINE
+ Fp t;
+ Fp::neg(t, Q.y);
+ if (P.y == t) { R.clear(); return; }
+ Fp::sub(t, Q.x, P.x);
+ if (t.isZero()) {
+ dblNoVerifyInf(R, P);
+ return;
+ }
+ Fp s;
+ Fp::sub(s, Q.y, P.y);
+ Fp::div(t, s, t);
+ R.inf_ = false;
+ Fp x3;
+ Fp::sqr(x3, t);
+ x3 -= P.x;
+ x3 -= Q.x;
+ Fp::sub(s, P.x, x3);
+ s *= t;
+ Fp::sub(R.y, s, P.y);
+ R.x = x3;
+#else
+ bool isPzOne = P.z.isOne();
+ bool isQzOne = Q.z.isOne();
+ switch (mode_) {
+ case ec::Jacobi:
+ addJacobi(R, P, Q, isPzOne, isQzOne);
+ break;
+ case ec::Proj:
+ addProj(R, P, Q, isPzOne, isQzOne);
+ break;
+ }
+#endif
+ }
+ static inline void sub(EcT& R, const EcT& P, const EcT& Q)
+ {
+ EcT nQ;
+ neg(nQ, Q);
+ add(R, P, nQ);
+ }
+ static inline void neg(EcT& R, const EcT& P)
+ {
+ if (P.isZero()) {
+ R.clear();
+ return;
+ }
+ R.x = P.x;
+ Fp::neg(R.y, P.y);
+#ifdef MCL_EC_USE_AFFINE
+ R.inf_ = false;
+#else
+ R.z = P.z;
+#endif
+ }
+ template<class tag, size_t maxBitSize, template<class _tag, size_t _maxBitSize>class FpT>
+ static inline void mul(EcT& z, const EcT& x, const FpT<tag, maxBitSize>& y)
+ {
+ fp::Block b;
+ y.getBlock(b);
+ mulArray(z, x, b.p, b.n, false);
+ }
+ static inline void mul(EcT& z, const EcT& x, int64_t y)
+ {
+ const uint64_t u = fp::abs_(y);
+#if MCL_SIZEOF_UNIT == 8
+ mulArray(z, x, &u, 1, y < 0);
+#else
+ uint32_t ua[2] = { uint32_t(u), uint32_t(u >> 32) };
+ size_t un = ua[1] ? 2 : 1;
+ mulArray(z, x, ua, un, y < 0);
+#endif
+ }
+ static inline void mul(EcT& z, const EcT& x, const mpz_class& y)
+ {
+ mulArray(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0);
+ }
+ template<class tag, size_t maxBitSize, template<class _tag, size_t _maxBitSize>class FpT>
+ static inline void mulCT(EcT& z, const EcT& x, const FpT<tag, maxBitSize>& y)
+ {
+ fp::Block b;
+ y.getBlock(b);
+ mulArray(z, x, b.p, b.n, false, true);
+ }
+ static inline void mulCT(EcT& z, const EcT& x, const mpz_class& y)
+ {
+ mulArray(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0, true);
+ }
+ /*
+ 0 <= P for any P
+ (Px, Py) <= (P'x, P'y) iff Px < P'x or Px == P'x and Py <= P'y
+ @note compare function calls normalize()
+ */
+ template<class F>
+ static inline int compareFunc(const EcT& P_, const EcT& Q_, F comp)
+ {
+ const bool QisZero = Q_.isZero();
+ if (P_.isZero()) {
+ if (QisZero) return 0;
+ return -1;
+ }
+ if (QisZero) return 1;
+ EcT P(P_), Q(Q_);
+ P.normalize();
+ Q.normalize();
+ int c = comp(P.x, Q.x);
+ if (c > 0) return 1;
+ if (c < 0) return -1;
+ return comp(P.y, Q.y);
+ }
+ static inline int compare(const EcT& P, const EcT& Q)
+ {
+ return compareFunc(P, Q, Fp::compare);
+ }
+ static inline int compareRaw(const EcT& P, const EcT& Q)
+ {
+ return compareFunc(P, Q, Fp::compareRaw);
+ }
+ bool isZero() const
+ {
+#ifdef MCL_EC_USE_AFFINE
+ return inf_;
+#else
+ return z.isZero();
+#endif
+ }
+ static inline bool isMSBserialize()
+ {
+ return !b_.isZero() && (Fp::BaseFp::getBitSize() & 7) != 0;
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ if (ioMode & IoEcProj) {
+ cybozu::writeChar(pb, os, '4'); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ x.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ y.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+#ifndef MCL_EC_USE_AFFINE
+ z.save(pb, os, ioMode);
+#endif
+ return;
+ }
+ EcT P(*this);
+ P.normalize();
+ if (ioMode & (IoSerialize | IoSerializeHexStr)) {
+ /*
+ if (isMSBserialize()) {
+ // n bytes
+ x | (y.isOdd ? 0x80 : 0)
+ } else {
+ // n + 1 bytes
+ (y.isOdd ? 3 : 2), x
+ }
+ */
+ const size_t n = Fp::getByteSize();
+ const size_t adj = isMSBserialize() ? 0 : 1;
+ char buf[sizeof(Fp) + 1];
+ if (isZero()) {
+ memset(buf, 0, n + adj);
+ } else {
+ cybozu::MemoryOutputStream mos(buf + adj, n);
+ P.x.save(pb, mos, IoSerialize); if (!*pb) return;
+ if (adj) {
+ buf[0] = P.y.isOdd() ? 3 : 2;
+ } else {
+ if (P.y.isOdd()) {
+ buf[n - 1] |= 0x80;
+ }
+ }
+ }
+ if (ioMode & IoSerializeHexStr) {
+ mcl::fp::writeHexStr(pb, os, buf, n + adj);
+ } else {
+ cybozu::write(pb, os, buf, n + adj);
+ }
+ return;
+ }
+ if (isZero()) {
+ cybozu::writeChar(pb, os, '0');
+ return;
+ }
+ if (ioMode & IoEcCompY) {
+ cybozu::writeChar(pb, os, P.y.isOdd() ? '3' : '2');
+ if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ P.x.save(pb, os, ioMode);
+ } else {
+ cybozu::writeChar(pb, os, '1'); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ P.x.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ P.y.save(pb, os, ioMode);
+ }
+ }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode)
+ {
+#ifdef MCL_EC_USE_AFFINE
+ inf_ = false;
+#else
+ z = 1;
+#endif
+ if (ioMode & (IoSerialize | IoSerializeHexStr)) {
+ const size_t n = Fp::getByteSize();
+ const size_t adj = isMSBserialize() ? 0 : 1;
+ const size_t n1 = n + adj;
+ char buf[sizeof(Fp) + 1];
+ size_t readSize;
+ if (ioMode & IoSerializeHexStr) {
+ readSize = mcl::fp::readHexStr(buf, n1, is);
+ } else {
+ readSize = cybozu::readSome(buf, n1, is);
+ }
+ if (readSize != n1) {
+ *pb = false;
+ return;
+ }
+ if (fp::isZeroArray(buf, n1)) {
+ clear();
+ *pb = true;
+ return;
+ }
+ bool isYodd;
+ if (adj) {
+ char c = buf[0];
+ if (c != 2 && c != 3) {
+ *pb = false;
+ return;
+ }
+ isYodd = c == 3;
+ } else {
+ isYodd = (buf[n - 1] >> 7) != 0;
+ buf[n - 1] &= 0x7f;
+ }
+ x.setArray(pb, buf + adj, n);
+ if (!*pb) return;
+ *pb = getYfromX(y, x, isYodd);
+ if (!*pb) return;
+ } else {
+ char c = 0;
+ if (!fp::local::skipSpace(&c, is)) {
+ *pb = false;
+ return;
+ }
+ if (c == '0') {
+ clear();
+ *pb = true;
+ return;
+ }
+ x.load(pb, is, ioMode); if (!*pb) return;
+ if (c == '1') {
+ y.load(pb, is, ioMode); if (!*pb) return;
+ if (!isValid(x, y)) {
+ *pb = false;
+ return;
+ }
+ } else if (c == '2' || c == '3') {
+ bool isYodd = c == '3';
+ *pb = getYfromX(y, x, isYodd);
+ if (!*pb) return;
+ } else if (c == '4') {
+ y.load(pb, is, ioMode); if (!*pb) return;
+#ifndef MCL_EC_USE_AFFINE
+ z.load(pb, is, ioMode); if (!*pb) return;
+#endif
+ } else {
+ *pb = false;
+ return;
+ }
+ }
+ if (verifyOrder_ && !isValidOrder()) {
+ *pb = false;
+ } else {
+ *pb = true;
+ }
+ }
+ // deplicated
+ static void setCompressedExpression(bool compressedExpression = true)
+ {
+ if (compressedExpression) {
+ ioMode_ |= IoEcCompY;
+ } else {
+ ioMode_ &= ~IoEcCompY;
+ }
+ }
+ /*
+ set IoMode for operator<<(), or operator>>()
+ */
+ static void setIoMode(int ioMode)
+ {
+ assert(!(ioMode & 0xff));
+ ioMode_ = ioMode;
+ }
+ static inline int getIoMode() { return Fp::BaseFp::getIoMode() | ioMode_; }
+ static inline void getWeierstrass(Fp& yy, const Fp& x)
+ {
+ Fp t;
+ Fp::sqr(t, x);
+ t += a_;
+ t *= x;
+ Fp::add(yy, t, b_);
+ }
+ static inline bool getYfromX(Fp& y, const Fp& x, bool isYodd)
+ {
+ getWeierstrass(y, x);
+ if (!Fp::squareRoot(y, y)) {
+ return false;
+ }
+ if (y.isOdd() ^ isYodd) {
+ Fp::neg(y, y);
+ }
+ return true;
+ }
+ inline friend EcT operator+(const EcT& x, const EcT& y) { EcT z; add(z, x, y); return z; }
+ inline friend EcT operator-(const EcT& x, const EcT& y) { EcT z; sub(z, x, y); return z; }
+ template<class INT>
+ inline friend EcT operator*(const EcT& x, const INT& y) { EcT z; mul(z, x, y); return z; }
+ EcT& operator+=(const EcT& x) { add(*this, *this, x); return *this; }
+ EcT& operator-=(const EcT& x) { sub(*this, *this, x); return *this; }
+ template<class INT>
+ EcT& operator*=(const INT& x) { mul(*this, *this, x); return *this; }
+ EcT operator-() const { EcT x; neg(x, *this); return x; }
+ bool operator==(const EcT& rhs) const
+ {
+ EcT R;
+ sub(R, *this, rhs); // QQQ : optimized later
+ return R.isZero();
+ }
+ bool operator!=(const EcT& rhs) const { return !operator==(rhs); }
+ bool operator<(const EcT& rhs) const
+ {
+ return compare(*this, rhs) < 0;
+ }
+ bool operator>=(const EcT& rhs) const { return !operator<(rhs); }
+ bool operator>(const EcT& rhs) const { return rhs < *this; }
+ bool operator<=(const EcT& rhs) const { return !operator>(rhs); }
+ static inline void mulArray(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime = false)
+ {
+ if (!constTime && x.isZero()) {
+ z.clear();
+ return;
+ }
+ if (mulArrayGLV && (constTime || yn > 1)) {
+ mulArrayGLV(z, x, y, yn, isNegative, constTime);
+ return;
+ }
+ mulArrayBase(z, x, y, yn, isNegative, constTime);
+ }
+ static inline void mulArrayBase(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime)
+ {
+ EcT tmp;
+ const EcT *px = &x;
+ if (&z == &x) {
+ tmp = x;
+ px = &tmp;
+ }
+ z.clear();
+ fp::powGeneric(z, *px, y, yn, EcT::add, EcT::dbl, EcT::normalize, constTime ? Fp::BaseFp::getBitSize() : 0);
+ if (isNegative) {
+ neg(z, z);
+ }
+ }
+ /*
+ generic mul
+ */
+ static inline void mulGeneric(EcT& z, const EcT& x, const mpz_class& y, bool constTime = false)
+ {
+ mulArrayBase(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0, constTime);
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ static inline void init(const std::string& astr, const std::string& bstr, int mode = ec::Jacobi)
+ {
+ bool b;
+ init(&b, astr.c_str(), bstr.c_str(), mode);
+ if (!b) throw cybozu::Exception("mcl:EcT:init");
+ }
+ void set(const Fp& _x, const Fp& _y, bool verify = true)
+ {
+ bool b;
+ set(&b, _x, _y, verify);
+ if (!b) throw cybozu::Exception("ec:EcT:set") << _x << _y;
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("EcT:save");
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("EcT:load");
+ }
+#endif
+#ifndef CYBOZU_DONT_USE_STRING
+ // backward compatilibity
+ static inline void setParam(const std::string& astr, const std::string& bstr, int mode = ec::Jacobi)
+ {
+ init(astr, bstr, mode);
+ }
+ friend inline std::istream& operator>>(std::istream& is, EcT& self)
+ {
+ self.load(is, fp::detectIoMode(getIoMode(), is));
+ return is;
+ }
+ friend inline std::ostream& operator<<(std::ostream& os, const EcT& self)
+ {
+ self.save(os, fp::detectIoMode(getIoMode(), os));
+ return os;
+ }
+#endif
+};
+
+template<class Fp> Fp EcT<Fp>::a_;
+template<class Fp> Fp EcT<Fp>::b_;
+template<class Fp> int EcT<Fp>::specialA_;
+template<class Fp> int EcT<Fp>::ioMode_;
+template<class Fp> bool EcT<Fp>::verifyOrder_;
+template<class Fp> mpz_class EcT<Fp>::order_;
+template<class Fp> void (*EcT<Fp>::mulArrayGLV)(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime);
+#ifndef MCL_EC_USE_AFFINE
+template<class Fp> int EcT<Fp>::mode_;
+#endif
+
+struct EcParam {
+ const char *name;
+ const char *p;
+ const char *a;
+ const char *b;
+ const char *gx;
+ const char *gy;
+ const char *n;
+ size_t bitSize; // bit length of p
+ int curveType;
+};
+
+} // mcl
+
+#ifdef CYBOZU_USE_BOOST
+namespace mcl {
+template<class Fp>
+size_t hash_value(const mcl::EcT<Fp>& P_)
+{
+ if (P_.isZero()) return 0;
+ mcl::EcT<Fp> P(P_); P.normalize();
+ return mcl::hash_value(P.y, mcl::hash_value(P.x));
+}
+
+}
+#else
+namespace std { CYBOZU_NAMESPACE_TR1_BEGIN
+
+template<class Fp>
+struct hash<mcl::EcT<Fp> > {
+ size_t operator()(const mcl::EcT<Fp>& P_) const
+ {
+ if (P_.isZero()) return 0;
+ mcl::EcT<Fp> P(P_); P.normalize();
+ return hash<Fp>()(P.y, hash<Fp>()(P.x));
+ }
+};
+
+CYBOZU_NAMESPACE_TR1_END } // std
+#endif
+
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/ecdsa.h b/vendor/github.com/byzantine-lab/mcl/include/mcl/ecdsa.h
new file mode 100644
index 000000000..daeb6be53
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/ecdsa.h
@@ -0,0 +1,105 @@
+#pragma once
+/**
+ @file
+ @brief C interface of ECDSA
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <stdint.h> // for uint64_t, uint8_t
+#include <stdlib.h> // for size_t
+
+#if defined(_MSC_VER)
+ #ifdef ECDSA_DLL_EXPORT
+ #define ECDSA_DLL_API __declspec(dllexport)
+ #else
+ #define ECDSA_DLL_API __declspec(dllimport)
+ #ifndef ECDSA_NO_AUTOLINK
+ #pragma comment(lib, "mclecdsa.lib")
+ #endif
+ #endif
+#elif defined(__EMSCRIPTEN__)
+ #define ECDSA_DLL_API __attribute__((used))
+#else
+ #define ECDSA_DLL_API
+#endif
+
+#ifndef mclSize
+ #ifdef __EMSCRIPTEN__
+ // avoid 64-bit integer
+ #define mclSize unsigned int
+ #define mclInt int
+ #else
+ // use #define for cgo
+ #define mclSize size_t
+ #define mclInt int64_t
+ #endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef ECDSA_NOT_DEFINE_STRUCT
+
+typedef struct ecdsaSecretKey ecdsaSecretKey;
+typedef struct ecdsaPublicKey ecdsaPublicKey;
+typedef struct ecdsaSignature ecdsaSignature;
+
+#else
+
+typedef struct {
+ uint64_t d[4];
+} ecdsaSecretKey;
+
+typedef struct {
+ uint64_t d[4 * 3];
+} ecdsaPublicKey;
+
+typedef struct {
+ uint64_t d[4 * 2];
+} ecdsaSignature;
+
+#endif
+
+struct ecdsaPrecomputedPublicKey;
+
+/*
+ init library
+ return 0 if success
+ @note not threadsafe
+*/
+ECDSA_DLL_API int ecdsaInit(void);
+
+// return written byte size if success else 0
+ECDSA_DLL_API mclSize ecdsaSecretKeySerialize(void *buf, mclSize maxBufSize, const ecdsaSecretKey *sec);
+ECDSA_DLL_API mclSize ecdsaPublicKeySerialize(void *buf, mclSize maxBufSize, const ecdsaPublicKey *pub);
+ECDSA_DLL_API mclSize ecdsaSignatureSerialize(void *buf, mclSize maxBufSize, const ecdsaSignature *sig);
+
+// return read byte size if sucess else 0
+ECDSA_DLL_API mclSize ecdsaSecretKeyDeserialize(ecdsaSecretKey* sec, const void *buf, mclSize bufSize);
+ECDSA_DLL_API mclSize ecdsaPublicKeyDeserialize(ecdsaPublicKey* pub, const void *buf, mclSize bufSize);
+ECDSA_DLL_API mclSize ecdsaSignatureDeserialize(ecdsaSignature* sig, const void *buf, mclSize bufSize);
+
+// return 0 if success
+ECDSA_DLL_API int ecdsaSecretKeySetByCSPRNG(ecdsaSecretKey *sec);
+
+ECDSA_DLL_API void ecdsaGetPublicKey(ecdsaPublicKey *pub, const ecdsaSecretKey *sec);
+
+ECDSA_DLL_API void ecdsaSign(ecdsaSignature *sig, const ecdsaSecretKey *sec, const void *m, mclSize size);
+
+// return 1 if valid
+ECDSA_DLL_API int ecdsaVerify(const ecdsaSignature *sig, const ecdsaPublicKey *pub, const void *m, mclSize size);
+ECDSA_DLL_API int ecdsaVerifyPrecomputed(const ecdsaSignature *sig, const ecdsaPrecomputedPublicKey *pub, const void *m, mclSize size);
+
+// return nonzero if success
+ECDSA_DLL_API ecdsaPrecomputedPublicKey *ecdsaPrecomputedPublicKeyCreate();
+// call this function to avoid memory leak
+ECDSA_DLL_API void ecdsaPrecomputedPublicKeyDestroy(ecdsaPrecomputedPublicKey *ppub);
+// return 0 if success
+ECDSA_DLL_API int ecdsaPrecomputedPublicKeyInit(ecdsaPrecomputedPublicKey *ppub, const ecdsaPublicKey *pub);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/ecdsa.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/ecdsa.hpp
new file mode 100644
index 000000000..cf3ed3f65
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/ecdsa.hpp
@@ -0,0 +1,257 @@
+#pragma once
+/**
+ @file
+ @brief ECDSA
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/fp.hpp>
+#include <mcl/ec.hpp>
+#include <mcl/ecparam.hpp>
+#include <mcl/window_method.hpp>
+
+namespace mcl { namespace ecdsa {
+
+namespace local {
+
+#ifndef MCLSHE_WIN_SIZE
+ #define MCLSHE_WIN_SIZE 10
+#endif
+static const size_t winSize = MCLSHE_WIN_SIZE;
+
+struct FpTag;
+struct ZnTag;
+
+} // mcl::ecdsa::local
+
+typedef mcl::FpT<local::FpTag, 256> Fp;
+typedef mcl::FpT<local::ZnTag, 256> Zn;
+typedef mcl::EcT<Fp> Ec;
+
+namespace local {
+
+struct Param {
+ mcl::EcParam ecParam;
+ Ec P;
+ mcl::fp::WindowMethod<Ec> Pbase;
+};
+
+inline Param& getParam()
+{
+ static Param p;
+ return p;
+}
+
+inline void be32toZn(Zn& x, const mcl::fp::Unit *buf)
+{
+ const size_t n = 32;
+ const unsigned char *p = (const unsigned char*)buf;
+ unsigned char be[n];
+ for (size_t i = 0; i < n; i++) {
+ be[i] = p[n - 1 - i];
+ }
+ x.setArrayMaskMod(be, n);
+}
+
+/*
+ y = x mod n
+*/
+inline void FpToZn(Zn& y, const Fp& x)
+{
+ fp::Block b;
+ x.getBlock(b);
+ y.setArrayMaskMod(b.p, b.n);
+}
+
+inline void setHashOf(Zn& x, const void *msg, size_t msgSize)
+{
+ mcl::fp::Unit xBuf[256 / 8 / sizeof(mcl::fp::Unit)];
+ uint32_t hashSize = mcl::fp::sha256(xBuf, sizeof(xBuf), msg, (uint32_t)msgSize);
+ assert(hashSize == sizeof(xBuf));
+ (void)hashSize;
+ be32toZn(x, xBuf);
+}
+
+} // mcl::ecdsa::local
+
+const local::Param& param = local::getParam();
+
+inline void init(bool *pb)
+{
+ const mcl::EcParam& ecParam = mcl::ecparam::secp256k1;
+ Zn::init(pb, ecParam.n);
+ if (!*pb) return;
+ Fp::init(pb, ecParam.p);
+ if (!*pb) return;
+ Ec::init(pb, ecParam.a, ecParam.b);
+ if (!*pb) return;
+ Zn::setIoMode(16);
+ Fp::setIoMode(16);
+ Ec::setIoMode(mcl::IoEcAffine);
+ local::Param& p = local::getParam();
+ p.ecParam = ecParam;
+ Fp x, y;
+ x.setStr(pb, ecParam.gx);
+ if (!*pb) return;
+ y.setStr(pb, ecParam.gy);
+ if (!*pb) return;
+ p.P.set(pb, x, y);
+ if (!*pb) return;
+ p.Pbase.init(pb, p.P, ecParam.bitSize, local::winSize);
+}
+
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+inline void init()
+{
+ bool b;
+ init(&b);
+ if (!b) throw cybozu::Exception("ecdsa:init");
+}
+#endif
+
+typedef Zn SecretKey;
+typedef Ec PublicKey;
+
+struct PrecomputedPublicKey {
+ mcl::fp::WindowMethod<Ec> pubBase_;
+ void init(bool *pb, const PublicKey& pub)
+ {
+ pubBase_.init(pb, pub, param.ecParam.bitSize, local::winSize);
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ void init(const PublicKey& pub)
+ {
+ bool b;
+ init(&b, pub);
+ if (!b) throw cybozu::Exception("ecdsa:PrecomputedPublicKey:init");
+ }
+#endif
+};
+
+inline void getPublicKey(PublicKey& pub, const SecretKey& sec)
+{
+ Ec::mul(pub, param.P, sec);
+ pub.normalize();
+}
+
+struct Signature : public mcl::fp::Serializable<Signature> {
+ Zn r, s;
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
+ {
+ r.load(pb, is, ioMode); if (!*pb) return;
+ s.load(pb, is, ioMode);
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ r.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ s.save(pb, os, ioMode);
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("ecdsa:Signature:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("ecdsa:Signature:save");
+ }
+#endif
+#ifndef CYBOZU_DONT_USE_STRING
+ friend std::istream& operator>>(std::istream& is, Signature& self)
+ {
+ self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const Signature& self)
+ {
+ self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
+ return os;
+ }
+#endif
+};
+
+inline void sign(Signature& sig, const SecretKey& sec, const void *msg, size_t msgSize)
+{
+ Zn& r = sig.r;
+ Zn& s = sig.s;
+ Zn z, k;
+ local::setHashOf(z, msg, msgSize);
+ Ec Q;
+ for (;;) {
+ k.setByCSPRNG();
+ param.Pbase.mul(Q, k);
+ if (Q.isZero()) continue;
+ Q.normalize();
+ local::FpToZn(r, Q.x);
+ if (r.isZero()) continue;
+ Zn::mul(s, r, sec);
+ s += z;
+ if (s.isZero()) continue;
+ s /= k;
+ return;
+ }
+}
+
+namespace local {
+
+inline void mulDispatch(Ec& Q, const PublicKey& pub, const Zn& y)
+{
+ Ec::mul(Q, pub, y);
+}
+
+inline void mulDispatch(Ec& Q, const PrecomputedPublicKey& ppub, const Zn& y)
+{
+ ppub.pubBase_.mul(Q, y);
+}
+
+template<class Pub>
+inline bool verify(const Signature& sig, const Pub& pub, const void *msg, size_t msgSize)
+{
+ const Zn& r = sig.r;
+ const Zn& s = sig.s;
+ if (r.isZero() || s.isZero()) return false;
+ Zn z, w, u1, u2;
+ local::setHashOf(z, msg, msgSize);
+ Zn::inv(w, s);
+ Zn::mul(u1, z, w);
+ Zn::mul(u2, r, w);
+ Ec Q1, Q2;
+ param.Pbase.mul(Q1, u1);
+// Ec::mul(Q2, pub, u2);
+ local::mulDispatch(Q2, pub, u2);
+ Q1 += Q2;
+ if (Q1.isZero()) return false;
+ Q1.normalize();
+ Zn x;
+ local::FpToZn(x, Q1.x);
+ return r == x;
+}
+
+} // mcl::ecdsa::local
+
+inline bool verify(const Signature& sig, const PublicKey& pub, const void *msg, size_t msgSize)
+{
+ return local::verify(sig, pub, msg, msgSize);
+}
+
+inline bool verify(const Signature& sig, const PrecomputedPublicKey& ppub, const void *msg, size_t msgSize)
+{
+ return local::verify(sig, ppub, msg, msgSize);
+}
+
+} } // mcl::ecdsa
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/ecparam.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/ecparam.hpp
new file mode 100644
index 000000000..087bf8b6c
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/ecparam.hpp
@@ -0,0 +1,191 @@
+#pragma once
+/**
+ @file
+ @brief Elliptic curve parameter
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/ec.hpp>
+#include <mcl/curve_type.h>
+
+namespace mcl { namespace ecparam {
+
+const struct mcl::EcParam secp160k1 = {
+ "secp160k1",
+ "0xfffffffffffffffffffffffffffffffeffffac73",
+ "0",
+ "7",
+ "0x3b4c382ce37aa192a4019e763036f4f5dd4d7ebb",
+ "0x938cf935318fdced6bc28286531733c3f03c4fee",
+ "0x100000000000000000001b8fa16dfab9aca16b6b3",
+ 160,
+ -1
+};
+// p=2^160 + 7
+const struct mcl::EcParam p160_1 = {
+ "p160_1",
+ "0x10000000000000000000000000000000000000007",
+ "10",
+ "1343632762150092499701637438970764818528075565078",
+ "1",
+ "1236612389951462151661156731535316138439983579284",
+ "1461501637330902918203683518218126812711137002561",
+ 161,
+ -1
+};
+const struct mcl::EcParam secp192k1 = {
+ "secp192k1",
+ "0xfffffffffffffffffffffffffffffffffffffffeffffee37",
+ "0",
+ "3",
+ "0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7d",
+ "0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9d",
+ "0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d",
+ 192,
+ MCL_SECP192K1
+};
+const struct mcl::EcParam secp224k1 = {
+ "secp224k1",
+ "0xfffffffffffffffffffffffffffffffffffffffffffffffeffffe56d",
+ "0",
+ "5",
+ "0xa1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45c",
+ "0x7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5",
+ "0x10000000000000000000000000001dce8d2ec6184caf0a971769fb1f7",
+ 224,
+ MCL_SECP224K1
+};
+const struct mcl::EcParam secp256k1 = {
+ "secp256k1",
+ "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "0",
+ "7",
+ "0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ "0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ 256,
+ MCL_SECP256K1
+};
+const struct mcl::EcParam secp384r1 = {
+ "secp384r1",
+ "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff",
+ "-3",
+ "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
+ "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
+ "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973",
+ 384,
+ MCL_SECP384R1
+};
+const struct mcl::EcParam secp521r1 = {
+ "secp521r1",
+ "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "-3",
+ "0x51953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
+ "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+ "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
+ "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
+ 521,
+ MCL_SECP521R1
+};
+const struct mcl::EcParam NIST_P192 = {
+ "NIST_P192",
+ "0xfffffffffffffffffffffffffffffffeffffffffffffffff",
+ "-3",
+ "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
+ "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
+ "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811",
+ "0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
+ 192,
+ MCL_NIST_P192
+};
+const struct mcl::EcParam NIST_P224 = {
+ "NIST_P224",
+ "0xffffffffffffffffffffffffffffffff000000000000000000000001",
+ "-3",
+ "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
+ "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
+ "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d",
+ 224,
+ MCL_NIST_P224
+};
+const struct mcl::EcParam NIST_P256 = {
+ "NIST_P256",
+ "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
+ "-3",
+ "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+ "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+ "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
+ "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
+ 256,
+ MCL_NIST_P256
+};
+// same secp384r1
+const struct mcl::EcParam NIST_P384 = {
+ "NIST_P384",
+ "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff",
+ "-3",
+ "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
+ "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
+ "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973",
+ 384,
+ MCL_NIST_P384
+};
+// same secp521r1
+const struct mcl::EcParam NIST_P521 = {
+ "NIST_P521",
+ "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "-3",
+ "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
+ "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+ "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
+ "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
+ 521,
+ MCL_NIST_P521
+};
+
+} // mcl::ecparam
+
+#ifndef CYBOZU_DONT_USE_STRING
+static inline const mcl::EcParam* getEcParam(const std::string& name)
+{
+ static const mcl::EcParam *tbl[] = {
+ &ecparam::p160_1,
+ &ecparam::secp160k1,
+ &ecparam::secp192k1,
+ &ecparam::secp224k1,
+ &ecparam::secp256k1,
+ &ecparam::secp384r1,
+ &ecparam::secp521r1,
+
+ &ecparam::NIST_P192,
+ &ecparam::NIST_P224,
+ &ecparam::NIST_P256,
+ &ecparam::NIST_P384,
+ &ecparam::NIST_P521,
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ if (name == tbl[i]->name) return tbl[i];
+ }
+ throw cybozu::Exception("mcl::getEcParam:not support name") << name;
+}
+#endif
+
+inline const mcl::EcParam* getEcParam(int curve)
+{
+ switch (curve) {
+ case MCL_SECP192K1: return &ecparam::secp192k1;
+ case MCL_SECP224K1: return &ecparam::secp224k1;
+ case MCL_SECP256K1: return &ecparam::secp256k1;
+ case MCL_SECP384R1: return &ecparam::secp384r1;
+ case MCL_NIST_P192: return &ecparam::NIST_P192;
+ case MCL_NIST_P224: return &ecparam::NIST_P224;
+ case MCL_NIST_P256: return &ecparam::NIST_P256;
+ default: return 0;
+ }
+}
+
+} // mcl
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/elgamal.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/elgamal.hpp
new file mode 100644
index 000000000..431148508
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/elgamal.hpp
@@ -0,0 +1,612 @@
+#pragma once
+/**
+ @file
+ @brief lifted-ElGamal encryption
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+
+ original:
+ Copyright (c) 2014, National Institute of Advanced Industrial
+ Science and Technology All rights reserved.
+ This source file is subject to BSD 3-Clause license.
+*/
+#include <string>
+#include <sstream>
+#include <cybozu/unordered_map.hpp>
+#ifndef CYBOZU_UNORDERED_MAP_STD
+#include <map>
+#endif
+#include <cybozu/exception.hpp>
+#include <cybozu/itoa.hpp>
+#include <cybozu/atoi.hpp>
+#include <mcl/window_method.hpp>
+
+namespace mcl {
+
+template<class _Ec, class Zn>
+struct ElgamalT {
+ typedef _Ec Ec;
+ struct CipherText {
+ Ec c1;
+ Ec c2;
+ CipherText()
+ {
+ clear();
+ }
+ /*
+ (c1, c2) = (0, 0) is trivial valid ciphertext for m = 0
+ */
+ void clear()
+ {
+ c1.clear();
+ c2.clear();
+ }
+ /*
+ add encoded message with encoded message
+ input : this = Enc(m1), c = Enc(m2)
+ output : this = Enc(m1 + m2)
+ */
+ void add(const CipherText& c)
+ {
+ Ec::add(c1, c1, c.c1);
+ Ec::add(c2, c2, c.c2);
+ }
+ /*
+ mul by x
+ input : this = Enc(m), x
+ output : this = Enc(m x)
+ */
+ template<class N>
+ void mul(const N& x)
+ {
+ Ec::mul(c1, c1, x);
+ Ec::mul(c2, c2, x);
+ }
+ /*
+ negative encoded message
+ input : this = Enc(m)
+ output : this = Enc(-m)
+ */
+ void neg()
+ {
+ Ec::neg(c1, c1);
+ Ec::neg(c2, c2);
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ c1.load(is, ioMode);
+ c2.load(is, ioMode);
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ c1.save(os, ioMode);
+ if (sep) cybozu::writeChar(os, sep);
+ c2.save(os, ioMode);
+ }
+ void getStr(std::string& str, int ioMode = 0) const
+ {
+ str.clear();
+ cybozu::StringOutputStream os(str);
+ save(os, ioMode);
+ }
+ std::string getStr(int ioMode = 0) const
+ {
+ std::string str;
+ getStr(str, ioMode);
+ return str;
+ }
+ void setStr(const std::string& str, int ioMode = 0)
+ {
+ cybozu::StringInputStream is(str);
+ load(is, ioMode);
+ }
+ friend inline std::ostream& operator<<(std::ostream& os, const CipherText& self)
+ {
+ self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
+ return os;
+ }
+ friend inline std::istream& operator>>(std::istream& is, CipherText& self)
+ {
+ self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
+ return is;
+ }
+ // obsolete
+ std::string toStr() const { return getStr(); }
+ void fromStr(const std::string& str) { setStr(str); }
+ };
+ /*
+ Zero Knowledge Proof
+ cipher text with ZKP to ensure m = 0 or 1
+ http://dx.doi.org/10.1587/transfun.E96.A.1156
+ */
+ struct Zkp {
+ Zn c0, c1, s0, s1;
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ c0.load(is, ioMode);
+ c1.load(is, ioMode);
+ s0.load(is, ioMode);
+ s1.load(is, ioMode);
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ c0.save(os, ioMode);
+ if (sep) cybozu::writeChar(os, sep);
+ c1.save(os, ioMode);
+ if (sep) cybozu::writeChar(os, sep);
+ s0.save(os, ioMode);
+ if (sep) cybozu::writeChar(os, sep);
+ s1.save(os, ioMode);
+ }
+ void getStr(std::string& str, int ioMode = 0) const
+ {
+ str.clear();
+ cybozu::StringOutputStream os(str);
+ save(os, ioMode);
+ }
+ std::string getStr(int ioMode = 0) const
+ {
+ std::string str;
+ getStr(str, ioMode);
+ return str;
+ }
+ void setStr(const std::string& str, int ioMode = 0)
+ {
+ cybozu::StringInputStream is(str);
+ load(is, ioMode);
+ }
+ friend inline std::ostream& operator<<(std::ostream& os, const Zkp& self)
+ {
+ self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
+ return os;
+ }
+ friend inline std::istream& operator>>(std::istream& is, Zkp& self)
+ {
+ self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
+ return is;
+ }
+ // obsolete
+ std::string toStr() const { return getStr(); }
+ void fromStr(const std::string& str) { setStr(str); }
+ };
+
+ class PublicKey {
+ size_t bitSize;
+ Ec f;
+ Ec g;
+ Ec h;
+ bool enableWindowMethod_;
+ fp::WindowMethod<Ec> wm_f;
+ fp::WindowMethod<Ec> wm_g;
+ fp::WindowMethod<Ec> wm_h;
+ template<class N>
+ void mulDispatch(Ec& z, const Ec& x, const N& n, const fp::WindowMethod<Ec>& pw) const
+ {
+ if (enableWindowMethod_) {
+ pw.mul(z, n);
+ } else {
+ Ec::mul(z, x, n);
+ }
+ }
+ template<class N>
+ void mulF(Ec& z, const N& n) const { mulDispatch(z, f, n, wm_f); }
+ template<class N>
+ void mulG(Ec& z, const N& n) const { mulDispatch(z, g, n, wm_g); }
+ template<class N>
+ void mulH(Ec& z, const N& n) const { mulDispatch(z, h, n, wm_h); }
+ public:
+ PublicKey()
+ : bitSize(0)
+ , enableWindowMethod_(false)
+ {
+ }
+ void enableWindowMethod(size_t winSize = 10)
+ {
+ wm_f.init(f, bitSize, winSize);
+ wm_g.init(g, bitSize, winSize);
+ wm_h.init(h, bitSize, winSize);
+ enableWindowMethod_ = true;
+ }
+ const Ec& getF() const { return f; }
+ void init(size_t bitSize, const Ec& f, const Ec& g, const Ec& h)
+ {
+ this->bitSize = bitSize;
+ this->f = f;
+ this->g = g;
+ this->h = h;
+ enableWindowMethod_ = false;
+ enableWindowMethod();
+ }
+ /*
+ encode message
+ input : m
+ output : c = (c1, c2) = (g^u, h^u f^m)
+ */
+ void enc(CipherText& c, const Zn& m, fp::RandGen rg = fp::RandGen()) const
+ {
+ Zn u;
+ u.setRand(rg);
+ mulG(c.c1, u);
+ mulH(c.c2, u);
+ Ec t;
+ mulF(t, m);
+ Ec::add(c.c2, c.c2, t);
+ }
+ /*
+ encode message
+ input : m = 0 or 1
+ output : c (c1, c2), zkp
+ */
+ void encWithZkp(CipherText& c, Zkp& zkp, int m, fp::RandGen rg = fp::RandGen()) const
+ {
+ if (m != 0 && m != 1) {
+ throw cybozu::Exception("elgamal:PublicKey:encWithZkp") << m;
+ }
+ Zn u;
+ u.setRand(rg);
+ mulG(c.c1, u);
+ mulH(c.c2, u);
+ if (m) {
+ Ec::add(c.c2, c.c2, f);
+ Zn r1;
+ r1.setRand(rg);
+ zkp.c0.setRand(rg);
+ zkp.s0.setRand(rg);
+ Ec R01, R02, R11, R12;
+ Ec t1, t2;
+ mulG(t1, zkp.s0);
+ Ec::mul(t2, c.c1, zkp.c0);
+ Ec::sub(R01, t1, t2);
+ mulH(t1, zkp.s0);
+ Ec::mul(t2, c.c2, zkp.c0);
+ Ec::sub(R02, t1, t2);
+ mulG(R11, r1);
+ mulH(R12, r1);
+ std::ostringstream os;
+ os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << f << g << h;
+ Zn cc;
+ cc.setHashOf(os.str());
+ zkp.c1 = cc - zkp.c0;
+ zkp.s1 = r1 + zkp.c1 * u;
+ } else {
+ Zn r0;
+ r0.setRand(rg);
+ zkp.c1.setRand(rg);
+ zkp.s1.setRand(rg);
+ Ec R01, R02, R11, R12;
+ mulG(R01, r0);
+ mulH(R02, r0);
+ Ec t1, t2;
+ mulG(t1, zkp.s1);
+ Ec::mul(t2, c.c1, zkp.c1);
+ Ec::sub(R11, t1, t2);
+ mulH(t1, zkp.s1);
+ Ec::sub(t2, c.c2, f);
+ Ec::mul(t2, t2, zkp.c1);
+ Ec::sub(R12, t1, t2);
+ std::ostringstream os;
+ os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << f << g << h;
+ Zn cc;
+ cc.setHashOf(os.str());
+ zkp.c0 = cc - zkp.c1;
+ zkp.s0 = r0 + zkp.c0 * u;
+ }
+ }
+ /*
+ verify cipher text with ZKP
+ */
+ bool verify(const CipherText& c, const Zkp& zkp) const
+ {
+ Ec R01, R02, R11, R12;
+ Ec t1, t2;
+ mulG(t1, zkp.s0);
+ Ec::mul(t2, c.c1, zkp.c0);
+ Ec::sub(R01, t1, t2);
+ mulH(t1, zkp.s0);
+ Ec::mul(t2, c.c2, zkp.c0);
+ Ec::sub(R02, t1, t2);
+ mulG(t1, zkp.s1);
+ Ec::mul(t2, c.c1, zkp.c1);
+ Ec::sub(R11, t1, t2);
+ mulH(t1, zkp.s1);
+ Ec::sub(t2, c.c2, f);
+ Ec::mul(t2, t2, zkp.c1);
+ Ec::sub(R12, t1, t2);
+ std::ostringstream os;
+ os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << f << g << h;
+ Zn cc;
+ cc.setHashOf(os.str());
+ return cc == zkp.c0 + zkp.c1;
+ }
+ /*
+ rerandomize encoded message
+ input : c = (c1, c2)
+ output : c = (c1 g^v, c2 h^v)
+ */
+ void rerandomize(CipherText& c, fp::RandGen rg = fp::RandGen()) const
+ {
+ Zn v;
+ v.setRand(rg);
+ Ec t;
+ mulG(t, v);
+ Ec::add(c.c1, c.c1, t);
+ mulH(t, v);
+ Ec::add(c.c2, c.c2, t);
+ }
+ /*
+ add encoded message with plain message
+ input : c = Enc(m1) = (c1, c2), m2
+ ouput : c = Enc(m1 + m2) = (c1, c2 f^m2)
+ */
+ template<class N>
+ void add(CipherText& c, const N& m) const
+ {
+ Ec fm;
+ mulF(fm, m);
+ Ec::add(c.c2, c.c2, fm);
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ std::string s;
+ mcl::fp::local::loadWord(s, is);
+ bitSize = cybozu::atoi(s);
+ f.load(is, ioMode);
+ g.load(is, ioMode);
+ h.load(is, ioMode);
+ init(bitSize, f, g, h);
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ std::string s = cybozu::itoa(bitSize);
+ cybozu::write(os, s.c_str(), s.size());
+ cybozu::writeChar(os, ' ');
+
+ const char sep = *fp::getIoSeparator(ioMode);
+ f.save(os, ioMode);
+ if (sep) cybozu::writeChar(os, sep);
+ g.save(os, ioMode);
+ if (sep) cybozu::writeChar(os, sep);
+ h.save(os, ioMode);
+ if (sep) cybozu::writeChar(os, sep);
+ }
+ void getStr(std::string& str, int ioMode = 0) const
+ {
+ str.clear();
+ cybozu::StringOutputStream os(str);
+ save(os, ioMode);
+ }
+ std::string getStr(int ioMode = 0) const
+ {
+ std::string str;
+ getStr(str, ioMode);
+ return str;
+ }
+ void setStr(const std::string& str, int ioMode = 0)
+ {
+ cybozu::StringInputStream is(str);
+ load(is, ioMode);
+ }
+ friend inline std::ostream& operator<<(std::ostream& os, const PublicKey& self)
+ {
+ self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
+ return os;
+ }
+ friend inline std::istream& operator>>(std::istream& is, PublicKey& self)
+ {
+ self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
+ return is;
+ }
+ // obsolete
+ std::string toStr() const { return getStr(); }
+ void fromStr(const std::string& str) { setStr(str); }
+ };
+ /*
+ create table f^i for i in [rangeMin, rangeMax]
+ */
+ struct PowerCache {
+#if (CYBOZU_CPP_VERSION > CYBOZU_CPP_VERSION_CP03)
+ typedef CYBOZU_NAMESPACE_STD::unordered_map<Ec, int> Cache;
+#else
+ typedef std::map<Ec, int> Cache;
+#endif
+ Cache cache;
+ void init(const Ec& f, int rangeMin, int rangeMax)
+ {
+ if (rangeMin > rangeMax) throw cybozu::Exception("mcl:ElgamalT:PowerCache:bad range") << rangeMin << rangeMax;
+ Ec x;
+ x.clear();
+ cache[x] = 0;
+ for (int i = 1; i <= rangeMax; i++) {
+ Ec::add(x, x, f);
+ cache[x] = i;
+ }
+ Ec nf;
+ Ec::neg(nf, f);
+ x.clear();
+ for (int i = -1; i >= rangeMin; i--) {
+ Ec::add(x, x, nf);
+ cache[x] = i;
+ }
+ }
+ /*
+ return m such that f^m = g
+ */
+ int getExponent(const Ec& g, bool *b = 0) const
+ {
+ typename Cache::const_iterator i = cache.find(g);
+ if (i == cache.end()) {
+ if (b) {
+ *b = false;
+ return 0;
+ }
+ throw cybozu::Exception("Elgamal:PowerCache:getExponent:not found") << g;
+ }
+ if (b) *b = true;
+ return i->second;
+ }
+ void clear()
+ {
+ cache.clear();
+ }
+ bool isEmpty() const
+ {
+ return cache.empty();
+ }
+ };
+ class PrivateKey {
+ PublicKey pub;
+ Zn z;
+ PowerCache cache;
+ public:
+ /*
+ init
+ input : f
+ output : (g, h, z)
+ Ec = <f>
+ g in Ec
+ h = g^z
+ */
+ void init(const Ec& f, size_t bitSize, fp::RandGen rg = fp::RandGen())
+ {
+ Ec g, h;
+ z.setRand(rg);
+ Ec::mul(g, f, z);
+ z.setRand(rg);
+ Ec::mul(h, g, z);
+ pub.init(bitSize, f, g, h);
+ }
+ const PublicKey& getPublicKey() const { return pub; }
+ /*
+ decode message by brute-force attack
+ input : c = (c1, c2)
+ output : m
+ M = c2 / c1^z
+ find m such that M = f^m and |m| < limit
+ @memo 7sec@core i3 for m = 1e6
+ */
+ void dec(Zn& m, const CipherText& c, int limit = 100000) const
+ {
+ const Ec& f = pub.getF();
+ Ec c1z;
+ Ec::mul(c1z, c.c1, z);
+ if (c1z == c.c2) {
+ m = 0;
+ return;
+ }
+ Ec t1(c1z);
+ Ec t2(c.c2);
+ for (int i = 1; i < limit; i++) {
+ Ec::add(t1, t1, f);
+ if (t1 == c.c2) {
+ m = i;
+ return;
+ }
+ Ec::add(t2, t2, f);
+ if (t2 == c1z) {
+ m = -i;
+ return;
+ }
+ }
+ throw cybozu::Exception("elgamal:PrivateKey:dec:overflow");
+ }
+ /*
+ powfm = c2 / c1^z = f^m
+ */
+ void getPowerf(Ec& powfm, const CipherText& c) const
+ {
+ Ec c1z;
+ Ec::mul(c1z, c.c1, z);
+ Ec::sub(powfm, c.c2, c1z);
+ }
+ /*
+ set range of message to decode quickly
+ */
+ void setCache(int rangeMin, int rangeMax)
+ {
+ cache.init(pub.getF(), rangeMin, rangeMax);
+ }
+ /*
+ clear cache
+ */
+ void clearCache()
+ {
+ cache.clear();
+ }
+ /*
+ decode message by lookup table if !cache.isEmpty()
+ brute-force attack otherwise
+ input : c = (c1, c2)
+ b : set false if not found
+ return m
+ */
+ int dec(const CipherText& c, bool *b = 0) const
+ {
+ Ec powfm;
+ getPowerf(powfm, c);
+ return cache.getExponent(powfm, b);
+ }
+ /*
+ check whether c is encrypted zero message
+ */
+ bool isZeroMessage(const CipherText& c) const
+ {
+ Ec c1z;
+ Ec::mul(c1z, c.c1, z);
+ return c.c2 == c1z;
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ pub.load(is, ioMode);
+ z.load(is, ioMode);
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ pub.save(os, ioMode);
+ if (sep) cybozu::writeChar(os, sep);
+ z.save(os, ioMode);
+ }
+ void getStr(std::string& str, int ioMode = 0) const
+ {
+ str.clear();
+ cybozu::StringOutputStream os(str);
+ save(os, ioMode);
+ }
+ std::string getStr(int ioMode = 0) const
+ {
+ std::string str;
+ getStr(str, ioMode);
+ return str;
+ }
+ void setStr(const std::string& str, int ioMode = 0)
+ {
+ cybozu::StringInputStream is(str);
+ load(is, ioMode);
+ }
+ friend inline std::ostream& operator<<(std::ostream& os, const PrivateKey& self)
+ {
+ self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
+ return os;
+ }
+ friend inline std::istream& operator>>(std::istream& is, PrivateKey& self)
+ {
+ self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
+ return is;
+ }
+ std::string toStr() const { return getStr(); }
+ void fromStr(const std::string& str) { setStr(str); }
+ };
+};
+
+} // mcl
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/fp.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/fp.hpp
new file mode 100644
index 000000000..2e69729dd
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/fp.hpp
@@ -0,0 +1,661 @@
+#pragma once
+/**
+ @file
+ @brief finite field class
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#ifndef CYBOZU_DONT_USE_STRING
+#include <iosfwd>
+#endif
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable : 4127)
+ #pragma warning(disable : 4458)
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+ #ifndef MCL_NO_AUTOLINK
+ #ifdef NDEBUG
+ #pragma comment(lib, "mcl.lib")
+ #else
+ #pragma comment(lib, "mcl.lib")
+ #endif
+ #endif
+#endif
+#include <cybozu/hash.hpp>
+#include <cybozu/stream.hpp>
+#include <mcl/op.hpp>
+#include <mcl/util.hpp>
+#include <mcl/operator.hpp>
+#include <mcl/conversion.hpp>
+
+namespace mcl {
+
+struct FpTag;
+struct ZnTag;
+
+namespace fp {
+
+// copy src to dst as little endian
+void copyUnitToByteAsLE(uint8_t *dst, const Unit *src, size_t byteSize);
+// copy src to dst as little endian
+void copyByteToUnitAsLE(Unit *dst, const uint8_t *src, size_t byteSize);
+
+bool copyAndMask(Unit *y, const void *x, size_t xByteSize, const Op& op, MaskMode maskMode);
+
+uint64_t getUint64(bool *pb, const fp::Block& b);
+int64_t getInt64(bool *pb, fp::Block& b, const fp::Op& op);
+
+const char *ModeToStr(Mode mode);
+
+Mode StrToMode(const char *s);
+
+#ifndef CYBOZU_DONT_USE_STRING
+inline Mode StrToMode(const std::string& s)
+{
+ return StrToMode(s.c_str());
+}
+#endif
+
+inline void dumpUnit(Unit x)
+{
+#if MCL_SIZEOF_UNIT == 4
+ printf("%08x", (uint32_t)x);
+#else
+ printf("%016llx", (unsigned long long)x);
+#endif
+}
+
+bool isEnableJIT(); // 1st call is not threadsafe
+
+uint32_t sha256(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);
+uint32_t sha512(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);
+
+} // mcl::fp
+
+template<class tag = FpTag, size_t maxBitSize = MCL_MAX_BIT_SIZE>
+class FpT : public fp::Serializable<FpT<tag, maxBitSize>,
+ fp::Operator<FpT<tag, maxBitSize> > > {
+ typedef fp::Unit Unit;
+ typedef fp::Operator<FpT<tag, maxBitSize> > Operator;
+ typedef fp::Serializable<FpT<tag, maxBitSize>, Operator> Serializer;
+public:
+ static const size_t maxSize = (maxBitSize + fp::UnitBitSize - 1) / fp::UnitBitSize;
+private:
+ template<class tag2, size_t maxBitSize2> friend class FpT;
+ Unit v_[maxSize];
+ static fp::Op op_;
+ static FpT<tag, maxBitSize> inv2_;
+ static int ioMode_;
+ template<class Fp> friend class FpDblT;
+ template<class Fp> friend class Fp2T;
+ template<class Fp> friend struct Fp6T;
+public:
+ typedef FpT<tag, maxBitSize> BaseFp;
+ // return pointer to array v_[]
+ const Unit *getUnit() const { return v_; }
+ FpT* getFp0() { return this; }
+ const FpT* getFp0() const { return this; }
+ static inline size_t getUnitSize() { return op_.N; }
+ static inline size_t getBitSize() { return op_.bitSize; }
+ static inline size_t getByteSize() { return (op_.bitSize + 7) / 8; }
+ static inline const fp::Op& getOp() { return op_; }
+ void dump() const
+ {
+ const size_t N = op_.N;
+ for (size_t i = 0; i < N; i++) {
+ fp::dumpUnit(v_[N - 1 - i]);
+ }
+ printf("\n");
+ }
+ /*
+ xi_a is used for Fp2::mul_xi(), where xi = xi_a + i and i^2 = -1
+ if xi_a = 0 then asm functions for Fp2 are not generated.
+ */
+ static inline void init(bool *pb, int xi_a, const mpz_class& p, fp::Mode mode = fp::FP_AUTO)
+ {
+ assert(maxBitSize <= MCL_MAX_BIT_SIZE);
+ *pb = op_.init(p, maxBitSize, xi_a, mode);
+ if (!*pb) return;
+ { // set oneRep
+ FpT& one = *reinterpret_cast<FpT*>(op_.oneRep);
+ one.clear();
+ one.v_[0] = 1;
+ one.toMont();
+ }
+ { // set half
+ mpz_class half = (op_.mp + 1) / 2;
+ gmp::getArray(pb, op_.half, op_.N, half);
+ if (!*pb) return;
+ }
+ inv(inv2_, 2);
+#ifdef MCL_XBYAK_DIRECT_CALL
+ add = fp::func_ptr_cast<void (*)(FpT& z, const FpT& x, const FpT& y)>(op_.fp_addA_);
+ if (add == 0) add = addC;
+ sub = fp::func_ptr_cast<void (*)(FpT& z, const FpT& x, const FpT& y)>(op_.fp_subA_);
+ if (sub == 0) sub = subC;
+ neg = fp::func_ptr_cast<void (*)(FpT& y, const FpT& x)>(op_.fp_negA_);
+ if (neg == 0) neg = negC;
+ mul = fp::func_ptr_cast<void (*)(FpT& z, const FpT& x, const FpT& y)>(op_.fp_mulA_);
+ if (mul == 0) mul = mulC;
+ sqr = fp::func_ptr_cast<void (*)(FpT& y, const FpT& x)>(op_.fp_sqrA_);
+ if (sqr == 0) sqr = sqrC;
+#endif
+ *pb = true;
+ }
+ static inline void init(bool *pb, const mpz_class& p, fp::Mode mode = fp::FP_AUTO)
+ {
+ init(pb, 0, p, mode);
+ }
+ static inline void init(bool *pb, const char *mstr, fp::Mode mode = fp::FP_AUTO)
+ {
+ mpz_class p;
+ gmp::setStr(pb, p, mstr);
+ if (!*pb) return;
+ init(pb, p, mode);
+ }
+ static inline size_t getModulo(char *buf, size_t bufSize)
+ {
+ return gmp::getStr(buf, bufSize, op_.mp);
+ }
+ static inline bool isFullBit() { return op_.isFullBit; }
+ /*
+ binary patter of p
+ @note the value of p is zero
+ */
+ static inline const FpT& getP()
+ {
+ return *reinterpret_cast<const FpT*>(op_.p);
+ }
+ bool isOdd() const
+ {
+ fp::Block b;
+ getBlock(b);
+ return (b.p[0] & 1) == 1;
+ }
+ static inline bool squareRoot(FpT& y, const FpT& x)
+ {
+ if (isMont()) return op_.sq.get(y, x);
+ mpz_class mx, my;
+ bool b = false;
+ x.getMpz(&b, mx);
+ if (!b) return false;
+ b = op_.sq.get(my, mx);
+ if (!b) return false;
+ y.setMpz(&b, my);
+ return b;
+ }
+ FpT() {}
+ FpT(const FpT& x)
+ {
+ op_.fp_copy(v_, x.v_);
+ }
+ FpT& operator=(const FpT& x)
+ {
+ op_.fp_copy(v_, x.v_);
+ return *this;
+ }
+ void clear()
+ {
+ op_.fp_clear(v_);
+ }
+ FpT(int64_t x) { operator=(x); }
+ FpT& operator=(int64_t x)
+ {
+ if (x == 1) {
+ op_.fp_copy(v_, op_.oneRep);
+ } else {
+ clear();
+ if (x) {
+ int64_t y = x < 0 ? -x : x;
+ if (sizeof(Unit) == 8) {
+ v_[0] = y;
+ } else {
+ v_[0] = (uint32_t)y;
+ v_[1] = (uint32_t)(y >> 32);
+ }
+ if (x < 0) neg(*this, *this);
+ toMont();
+ }
+ }
+ return *this;
+ }
+ static inline bool isMont() { return op_.isMont; }
+ /*
+ convert normal value to Montgomery value
+ do nothing is !isMont()
+ */
+ void toMont()
+ {
+ if (isMont()) op_.toMont(v_, v_);
+ }
+ /*
+ convert Montgomery value to normal value
+ do nothing is !isMont()
+ */
+ void fromMont()
+ {
+ if (isMont()) op_.fromMont(v_, v_);
+ }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode)
+ {
+ bool isMinus = false;
+ *pb = false;
+ if (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr)) {
+ const size_t n = getByteSize();
+ v_[op_.N - 1] = 0;
+ size_t readSize;
+ if (ioMode & IoSerializeHexStr) {
+ readSize = mcl::fp::readHexStr(v_, n, is);
+ } else {
+ readSize = cybozu::readSome(v_, n, is);
+ }
+ if (readSize != n) return;
+ } else {
+ char buf[1024];
+ size_t n = fp::local::loadWord(buf, sizeof(buf), is);
+ if (n == 0) return;
+ n = fp::strToArray(&isMinus, v_, op_.N, buf, n, ioMode);
+ if (n == 0) return;
+ for (size_t i = n; i < op_.N; i++) v_[i] = 0;
+ }
+ if (fp::isGreaterOrEqualArray(v_, op_.p, op_.N)) {
+ return;
+ }
+ if (isMinus) {
+ neg(*this, *this);
+ }
+ if (!(ioMode & IoArrayRaw)) {
+ toMont();
+ }
+ *pb = true;
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode) const
+ {
+ const size_t n = getByteSize();
+ if (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr)) {
+ if (ioMode & IoArrayRaw) {
+ cybozu::write(pb, os, v_, n);
+ } else {
+ fp::Block b;
+ getBlock(b);
+ if (ioMode & IoSerializeHexStr) {
+ mcl::fp::writeHexStr(pb, os, b.p, n);
+ } else {
+ cybozu::write(pb, os, b.p, n);
+ }
+ }
+ return;
+ }
+ fp::Block b;
+ getBlock(b);
+ // use low 8-bit ioMode for (base, withPrefix)
+ char buf[2048];
+ size_t len = mcl::fp::arrayToStr(buf, sizeof(buf), b.p, b.n, ioMode & 31, (ioMode & IoPrefix) != 0);
+ if (len == 0) {
+ *pb = false;
+ return;
+ }
+ cybozu::write(pb, os, buf + sizeof(buf) - len, len);
+ }
+ /*
+ mode = Mod : set x mod p if sizeof(S) * n <= 64 else error
+ */
+ template<class S>
+ void setArray(bool *pb, const S *x, size_t n, mcl::fp::MaskMode mode = fp::NoMask)
+ {
+ *pb = fp::copyAndMask(v_, x, sizeof(S) * n, op_, mode);
+ toMont();
+ }
+ /*
+ mask x with (1 << bitLen) and subtract p if x >= p
+ */
+ template<class S>
+ void setArrayMaskMod(const S *x, size_t n)
+ {
+ fp::copyAndMask(v_, x, sizeof(S) * n, op_, fp::MaskAndMod);
+ toMont();
+ }
+
+ /*
+ mask x with (1 << (bitLen - 1)) - 1 if x >= p
+ */
+ template<class S>
+ void setArrayMask(const S *x, size_t n)
+ {
+ fp::copyAndMask(v_, x, sizeof(S) * n, op_, fp::SmallMask);
+ toMont();
+ }
+ void getBlock(fp::Block& b) const
+ {
+ b.n = op_.N;
+ if (isMont()) {
+ op_.fromMont(b.v_, v_);
+ b.p = &b.v_[0];
+ } else {
+ b.p = &v_[0];
+ }
+ }
+ void setByCSPRNG(bool *pb, fp::RandGen rg = fp::RandGen())
+ {
+ if (rg.isZero()) rg = fp::RandGen::get();
+ rg.read(pb, v_, op_.N * sizeof(Unit)); // byte size
+ if (!pb) return;
+ setArrayMask(v_, op_.N);
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ void setByCSPRNG(fp::RandGen rg = fp::RandGen())
+ {
+ bool b;
+ setByCSPRNG(&b, rg);
+ if (!b) throw cybozu::Exception("setByCSPRNG");
+ }
+#endif
+ void setRand(fp::RandGen rg = fp::RandGen()) // old api
+ {
+ setByCSPRNG(rg);
+ }
+ /*
+ hash msg and mask with (1 << (bitLen - 1)) - 1
+ */
+ void setHashOf(const void *msg, size_t msgSize)
+ {
+ char buf[MCL_MAX_HASH_BIT_SIZE / 8];
+ uint32_t size = op_.hash(buf, static_cast<uint32_t>(sizeof(buf)), msg, static_cast<uint32_t>(msgSize));
+ setArrayMask(buf, size);
+ }
+ void getMpz(bool *pb, mpz_class& x) const
+ {
+ fp::Block b;
+ getBlock(b);
+ gmp::setArray(pb, x, b.p, b.n);
+ }
+ void setMpz(bool *pb, const mpz_class& x)
+ {
+ if (x < 0) {
+ *pb = false;
+ return;
+ }
+ setArray(pb, gmp::getUnit(x), gmp::getUnitSize(x));
+ }
+#ifdef MCL_XBYAK_DIRECT_CALL
+ static void (*add)(FpT& z, const FpT& x, const FpT& y);
+ static inline void addC(FpT& z, const FpT& x, const FpT& y) { op_.fp_add(z.v_, x.v_, y.v_, op_.p); }
+ static void (*sub)(FpT& z, const FpT& x, const FpT& y);
+ static inline void subC(FpT& z, const FpT& x, const FpT& y) { op_.fp_sub(z.v_, x.v_, y.v_, op_.p); }
+ static void (*neg)(FpT& y, const FpT& x);
+ static inline void negC(FpT& y, const FpT& x) { op_.fp_neg(y.v_, x.v_, op_.p); }
+ static void (*mul)(FpT& z, const FpT& x, const FpT& y);
+ static inline void mulC(FpT& z, const FpT& x, const FpT& y) { op_.fp_mul(z.v_, x.v_, y.v_, op_.p); }
+ static void (*sqr)(FpT& y, const FpT& x);
+ static inline void sqrC(FpT& y, const FpT& x) { op_.fp_sqr(y.v_, x.v_, op_.p); }
+#else
+ static inline void add(FpT& z, const FpT& x, const FpT& y) { op_.fp_add(z.v_, x.v_, y.v_, op_.p); }
+ static inline void sub(FpT& z, const FpT& x, const FpT& y) { op_.fp_sub(z.v_, x.v_, y.v_, op_.p); }
+ static inline void neg(FpT& y, const FpT& x) { op_.fp_neg(y.v_, x.v_, op_.p); }
+ static inline void mul(FpT& z, const FpT& x, const FpT& y) { op_.fp_mul(z.v_, x.v_, y.v_, op_.p); }
+ static inline void sqr(FpT& y, const FpT& x) { op_.fp_sqr(y.v_, x.v_, op_.p); }
+#endif
+ static inline void addPre(FpT& z, const FpT& x, const FpT& y) { op_.fp_addPre(z.v_, x.v_, y.v_); }
+ static inline void subPre(FpT& z, const FpT& x, const FpT& y) { op_.fp_subPre(z.v_, x.v_, y.v_); }
+ static inline void mulUnit(FpT& z, const FpT& x, const Unit y)
+ {
+ if (mulSmallUnit(z, x, y)) return;
+ op_.fp_mulUnit(z.v_, x.v_, y, op_.p);
+ }
+ static inline void inv(FpT& y, const FpT& x) { op_.fp_invOp(y.v_, x.v_, op_); }
+ static inline void divBy2(FpT& y, const FpT& x)
+ {
+#if 0
+ mul(y, x, inv2_);
+#else
+ bool odd = (x.v_[0] & 1) != 0;
+ op_.fp_shr1(y.v_, x.v_);
+ if (odd) {
+ op_.fp_addPre(y.v_, y.v_, op_.half);
+ }
+#endif
+ }
+ static inline void divBy4(FpT& y, const FpT& x)
+ {
+ divBy2(y, x); // QQQ : optimize later
+ divBy2(y, y);
+ }
+ bool isZero() const { return op_.fp_isZero(v_); }
+ bool isOne() const { return fp::isEqualArray(v_, op_.oneRep, op_.N); }
+ static const inline FpT& one() { return *reinterpret_cast<const FpT*>(op_.oneRep); }
+ /*
+ half = (p + 1) / 2
+ return true if half <= x < p
+ return false if 0 <= x < half
+ */
+ bool isNegative() const
+ {
+ fp::Block b;
+ getBlock(b);
+ return fp::isGreaterOrEqualArray(b.p, op_.half, op_.N);
+ }
+ bool isValid() const
+ {
+ return fp::isLessArray(v_, op_.p, op_.N);
+ }
+ uint64_t getUint64(bool *pb) const
+ {
+ fp::Block b;
+ getBlock(b);
+ return fp::getUint64(pb, b);
+ }
+ int64_t getInt64(bool *pb) const
+ {
+ fp::Block b;
+ getBlock(b);
+ return fp::getInt64(pb, b, op_);
+ }
+ bool operator==(const FpT& rhs) const { return fp::isEqualArray(v_, rhs.v_, op_.N); }
+ bool operator!=(const FpT& rhs) const { return !operator==(rhs); }
+ /*
+ @note
+ this compare functions is slow because of calling mul if isMont is true.
+ */
+ static inline int compare(const FpT& x, const FpT& y)
+ {
+ fp::Block xb, yb;
+ x.getBlock(xb);
+ y.getBlock(yb);
+ return fp::compareArray(xb.p, yb.p, op_.N);
+ }
+ bool isLess(const FpT& rhs) const
+ {
+ fp::Block xb, yb;
+ getBlock(xb);
+ rhs.getBlock(yb);
+ return fp::isLessArray(xb.p, yb.p, op_.N);
+ }
+ bool operator<(const FpT& rhs) const { return isLess(rhs); }
+ bool operator>=(const FpT& rhs) const { return !operator<(rhs); }
+ bool operator>(const FpT& rhs) const { return rhs < *this; }
+ bool operator<=(const FpT& rhs) const { return !operator>(rhs); }
+ /*
+ @note
+ return unexpected order if isMont is set.
+ */
+ static inline int compareRaw(const FpT& x, const FpT& y)
+ {
+ return fp::compareArray(x.v_, y.v_, op_.N);
+ }
+ bool isLessRaw(const FpT& rhs) const
+ {
+ return fp::isLessArray(v_, rhs.v_, op_.N);
+ }
+ /*
+ set IoMode for operator<<(), or operator>>()
+ */
+ static inline void setIoMode(int ioMode)
+ {
+ ioMode_ = ioMode;
+ }
+ static inline int getIoMode() { return ioMode_; }
+ static inline size_t getModBitLen() { return getBitSize(); }
+ static inline void setHashFunc(uint32_t hash(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize))
+ {
+ op_.hash = hash;
+ }
+#ifndef CYBOZU_DONT_USE_STRING
+ explicit FpT(const std::string& str, int base = 0)
+ {
+ Serializer::setStr(str, base);
+ }
+ static inline void getModulo(std::string& pstr)
+ {
+ gmp::getStr(pstr, op_.mp);
+ }
+ static std::string getModulo()
+ {
+ std::string s;
+ getModulo(s);
+ return s;
+ }
+ void setHashOf(const std::string& msg)
+ {
+ setHashOf(msg.data(), msg.size());
+ }
+ // backward compatibility
+ static inline void setModulo(const std::string& mstr, fp::Mode mode = fp::FP_AUTO)
+ {
+ init(mstr, mode);
+ }
+ friend inline std::ostream& operator<<(std::ostream& os, const FpT& self)
+ {
+ self.save(os, fp::detectIoMode(getIoMode(), os));
+ return os;
+ }
+ friend inline std::istream& operator>>(std::istream& is, FpT& self)
+ {
+ self.load(is, fp::detectIoMode(getIoMode(), is));
+ return is;
+ }
+#endif
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ static inline void init(int xi_a, const mpz_class& p, fp::Mode mode = fp::FP_AUTO)
+ {
+ bool b;
+ init(&b, xi_a, p, mode);
+ if (!b) throw cybozu::Exception("Fp:init");
+ }
+ static inline void init(int xi_a, const std::string& mstr, fp::Mode mode = fp::FP_AUTO)
+ {
+ mpz_class p;
+ gmp::setStr(p, mstr);
+ init(xi_a, p, mode);
+ }
+ static inline void init(const mpz_class& p, fp::Mode mode = fp::FP_AUTO)
+ {
+ init(0, p, mode);
+ }
+ static inline void init(const std::string& mstr, fp::Mode mode = fp::FP_AUTO)
+ {
+ init(0, mstr, mode);
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("fp:save") << ioMode;
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("fp:load") << ioMode;
+ }
+ /*
+ throw exception if x >= p
+ */
+ template<class S>
+ void setArray(const S *x, size_t n)
+ {
+ bool b;
+ setArray(&b, x, n);
+ if (!b) throw cybozu::Exception("Fp:setArray");
+ }
+ void setMpz(const mpz_class& x)
+ {
+ bool b;
+ setMpz(&b, x);
+ if (!b) throw cybozu::Exception("Fp:setMpz");
+ }
+ uint64_t getUint64() const
+ {
+ bool b;
+ uint64_t v = getUint64(&b);
+ if (!b) throw cybozu::Exception("Fp:getUint64:large value");
+ return v;
+ }
+ int64_t getInt64() const
+ {
+ bool b;
+ int64_t v = getInt64(&b);
+ if (!b) throw cybozu::Exception("Fp:getInt64:large value");
+ return v;
+ }
+ void getMpz(mpz_class& x) const
+ {
+ bool b;
+ getMpz(&b, x);
+ if (!b) throw cybozu::Exception("Fp:getMpz");
+ }
+ mpz_class getMpz() const
+ {
+ mpz_class x;
+ getMpz(x);
+ return x;
+ }
+#endif
+};
+
+template<class tag, size_t maxBitSize> fp::Op FpT<tag, maxBitSize>::op_;
+template<class tag, size_t maxBitSize> FpT<tag, maxBitSize> FpT<tag, maxBitSize>::inv2_;
+template<class tag, size_t maxBitSize> int FpT<tag, maxBitSize>::ioMode_ = IoAuto;
+#ifdef MCL_XBYAK_DIRECT_CALL
+template<class tag, size_t maxBitSize> void (*FpT<tag, maxBitSize>::add)(FpT& z, const FpT& x, const FpT& y);
+template<class tag, size_t maxBitSize> void (*FpT<tag, maxBitSize>::sub)(FpT& z, const FpT& x, const FpT& y);
+template<class tag, size_t maxBitSize> void (*FpT<tag, maxBitSize>::neg)(FpT& y, const FpT& x);
+template<class tag, size_t maxBitSize> void (*FpT<tag, maxBitSize>::mul)(FpT& z, const FpT& x, const FpT& y);
+template<class tag, size_t maxBitSize> void (*FpT<tag, maxBitSize>::sqr)(FpT& y, const FpT& x);
+#endif
+
+} // mcl
+
+#ifdef CYBOZU_USE_BOOST
+namespace mcl {
+
+template<class tag, size_t maxBitSize>
+size_t hash_value(const mcl::FpT<tag, maxBitSize>& x, size_t v = 0)
+{
+ return static_cast<size_t>(cybozu::hash64(x.getUnit(), x.getUnitSize(), v));
+}
+
+}
+#else
+namespace std { CYBOZU_NAMESPACE_TR1_BEGIN
+
+template<class tag, size_t maxBitSize>
+struct hash<mcl::FpT<tag, maxBitSize> > {
+ size_t operator()(const mcl::FpT<tag, maxBitSize>& x, uint64_t v = 0) const
+ {
+ return static_cast<size_t>(cybozu::hash64(x.getUnit(), x.getUnitSize(), v));
+ }
+};
+
+CYBOZU_NAMESPACE_TR1_END } // std::tr1
+#endif
+
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/fp_tower.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/fp_tower.hpp
new file mode 100644
index 000000000..95722e2d5
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/fp_tower.hpp
@@ -0,0 +1,1364 @@
+#pragma once
+/**
+ @file
+ @brief finite field extension class
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/fp.hpp>
+
+namespace mcl {
+
+template<class Fp>
+class FpDblT : public fp::Serializable<FpDblT<Fp> > {
+ typedef fp::Unit Unit;
+ Unit v_[Fp::maxSize * 2];
+public:
+ static size_t getUnitSize() { return Fp::op_.N * 2; }
+ FpDblT() : v_()
+ {
+ }
+ FpDblT(const FpDblT& rhs)
+ {
+ const size_t n = getUnitSize();
+ for (size_t i = 0; i < n; i++) {
+ v_[i] = rhs.v_[i];
+ }
+ }
+ void dump() const
+ {
+ const size_t n = getUnitSize();
+ for (size_t i = 0; i < n; i++) {
+ mcl::fp::dumpUnit(v_[n - 1 - i]);
+ }
+ printf("\n");
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int) const
+ {
+ char buf[1024];
+ size_t n = mcl::fp::arrayToHex(buf, sizeof(buf), v_, getUnitSize());
+ if (n == 0) {
+ *pb = false;
+ return;
+ }
+ cybozu::write(pb, os, buf + sizeof(buf) - n, sizeof(buf));
+ }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int)
+ {
+ char buf[1024];
+ *pb = false;
+ size_t n = fp::local::loadWord(buf, sizeof(buf), is);
+ if (n == 0) return;
+ n = fp::hexToArray(v_, getUnitSize(), buf, n);
+ if (n == 0) return;
+ for (size_t i = n; i < getUnitSize(); i++) v_[i] = 0;
+ *pb = true;
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("FpDblT:save") << ioMode;
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("FpDblT:load") << ioMode;
+ }
+ void getMpz(mpz_class& x) const
+ {
+ bool b;
+ getMpz(&b, x);
+ if (!b) throw cybozu::Exception("FpDblT:getMpz");
+ }
+ mpz_class getMpz() const
+ {
+ mpz_class x;
+ getMpz(x);
+ return x;
+ }
+#endif
+ void clear()
+ {
+ const size_t n = getUnitSize();
+ for (size_t i = 0; i < n; i++) {
+ v_[i] = 0;
+ }
+ }
+ FpDblT& operator=(const FpDblT& rhs)
+ {
+ const size_t n = getUnitSize();
+ for (size_t i = 0; i < n; i++) {
+ v_[i] = rhs.v_[i];
+ }
+ return *this;
+ }
+ // QQQ : does not check range of x strictly(use for debug)
+ void setMpz(const mpz_class& x)
+ {
+ assert(x >= 0);
+ const size_t xn = gmp::getUnitSize(x);
+ const size_t N2 = getUnitSize();
+ if (xn > N2) {
+ assert(0);
+ return;
+ }
+ memcpy(v_, gmp::getUnit(x), xn * sizeof(Unit));
+ memset(v_ + xn, 0, (N2 - xn) * sizeof(Unit));
+ }
+ void getMpz(bool *pb, mpz_class& x) const
+ {
+ gmp::setArray(pb, x, v_, Fp::op_.N * 2);
+ }
+#ifdef MCL_XBYAK_DIRECT_CALL
+ static void (*add)(FpDblT& z, const FpDblT& x, const FpDblT& y);
+ static void (*sub)(FpDblT& z, const FpDblT& x, const FpDblT& y);
+ static void (*mod)(Fp& z, const FpDblT& xy);
+ static void (*addPre)(FpDblT& z, const FpDblT& x, const FpDblT& y);
+ static void (*subPre)(FpDblT& z, const FpDblT& x, const FpDblT& y);
+ static void addC(FpDblT& z, const FpDblT& x, const FpDblT& y) { Fp::op_.fpDbl_add(z.v_, x.v_, y.v_, Fp::op_.p); }
+ static void subC(FpDblT& z, const FpDblT& x, const FpDblT& y) { Fp::op_.fpDbl_sub(z.v_, x.v_, y.v_, Fp::op_.p); }
+ static void modC(Fp& z, const FpDblT& xy) { Fp::op_.fpDbl_mod(z.v_, xy.v_, Fp::op_.p); }
+ static void addPreC(FpDblT& z, const FpDblT& x, const FpDblT& y) { Fp::op_.fpDbl_addPre(z.v_, x.v_, y.v_); }
+ static void subPreC(FpDblT& z, const FpDblT& x, const FpDblT& y) { Fp::op_.fpDbl_subPre(z.v_, x.v_, y.v_); }
+#else
+ static void add(FpDblT& z, const FpDblT& x, const FpDblT& y) { Fp::op_.fpDbl_add(z.v_, x.v_, y.v_, Fp::op_.p); }
+ static void sub(FpDblT& z, const FpDblT& x, const FpDblT& y) { Fp::op_.fpDbl_sub(z.v_, x.v_, y.v_, Fp::op_.p); }
+ static void mod(Fp& z, const FpDblT& xy) { Fp::op_.fpDbl_mod(z.v_, xy.v_, Fp::op_.p); }
+ static void addPre(FpDblT& z, const FpDblT& x, const FpDblT& y) { Fp::op_.fpDbl_addPre(z.v_, x.v_, y.v_); }
+ static void subPre(FpDblT& z, const FpDblT& x, const FpDblT& y) { Fp::op_.fpDbl_subPre(z.v_, x.v_, y.v_); }
+#endif
+ static void mulPreC(FpDblT& xy, const Fp& x, const Fp& y) { Fp::op_.fpDbl_mulPre(xy.v_, x.v_, y.v_); }
+ static void sqrPreC(FpDblT& xx, const Fp& x) { Fp::op_.fpDbl_sqrPre(xx.v_, x.v_); }
+ /*
+ mul(z, x, y) = mulPre(xy, x, y) + mod(z, xy)
+ */
+ static void (*mulPre)(FpDblT& xy, const Fp& x, const Fp& y);
+ static void (*sqrPre)(FpDblT& xx, const Fp& x);
+ static void mulUnit(FpDblT& z, const FpDblT& x, Unit y)
+ {
+ if (mulSmallUnit(z, x, y)) return;
+ assert(0); // not supported y
+ }
+ static void init()
+ {
+ const mcl::fp::Op& op = Fp::getOp();
+#ifdef MCL_XBYAK_DIRECT_CALL
+ add = fp::func_ptr_cast<void (*)(FpDblT&, const FpDblT&, const FpDblT&)>(op.fpDbl_addA_);
+ if (add == 0) add = addC;
+ sub = fp::func_ptr_cast<void (*)(FpDblT&, const FpDblT&, const FpDblT&)>(op.fpDbl_subA_);
+ if (sub == 0) sub = subC;
+ mod = fp::func_ptr_cast<void (*)(Fp&, const FpDblT&)>(op.fpDbl_modA_);
+ if (mod == 0) mod = modC;
+ addPre = fp::func_ptr_cast<void (*)(FpDblT&, const FpDblT&, const FpDblT&)>(op.fpDbl_addPre);
+ if (addPre == 0) addPre = addPreC;
+ subPre = fp::func_ptr_cast<void (*)(FpDblT&, const FpDblT&, const FpDblT&)>(op.fpDbl_subPre);
+ if (subPre == 0) subPre = subPreC;
+#endif
+ if (op.fpDbl_mulPreA_) {
+ mulPre = fp::func_ptr_cast<void (*)(FpDblT&, const Fp&, const Fp&)>(op.fpDbl_mulPreA_);
+ } else {
+ mulPre = mulPreC;
+ }
+ if (op.fpDbl_sqrPreA_) {
+ sqrPre = fp::func_ptr_cast<void (*)(FpDblT&, const Fp&)>(op.fpDbl_sqrPreA_);
+ } else {
+ sqrPre = sqrPreC;
+ }
+ }
+ void operator+=(const FpDblT& x) { add(*this, *this, x); }
+ void operator-=(const FpDblT& x) { sub(*this, *this, x); }
+};
+
+#ifdef MCL_XBYAK_DIRECT_CALL
+template<class Fp> void (*FpDblT<Fp>::add)(FpDblT&, const FpDblT&, const FpDblT&);
+template<class Fp> void (*FpDblT<Fp>::sub)(FpDblT&, const FpDblT&, const FpDblT&);
+template<class Fp> void (*FpDblT<Fp>::mod)(Fp&, const FpDblT&);
+template<class Fp> void (*FpDblT<Fp>::addPre)(FpDblT&, const FpDblT&, const FpDblT&);
+template<class Fp> void (*FpDblT<Fp>::subPre)(FpDblT&, const FpDblT&, const FpDblT&);
+#endif
+template<class Fp> void (*FpDblT<Fp>::mulPre)(FpDblT&, const Fp&, const Fp&);
+template<class Fp> void (*FpDblT<Fp>::sqrPre)(FpDblT&, const Fp&);
+
+template<class Fp> struct Fp12T;
+template<class Fp> class BNT;
+template<class Fp> struct Fp2DblT;
+/*
+ beta = -1
+ Fp2 = F[i] / (i^2 + 1)
+ x = a + bi
+*/
+template<class _Fp>
+class Fp2T : public fp::Serializable<Fp2T<_Fp>,
+ fp::Operator<Fp2T<_Fp> > > {
+ typedef _Fp Fp;
+ typedef fp::Unit Unit;
+ typedef FpDblT<Fp> FpDbl;
+ typedef Fp2DblT<Fp> Fp2Dbl;
+ static const size_t gN = 5;
+ /*
+ g = xi^((p - 1) / 6)
+ g[] = { g^2, g^4, g^1, g^3, g^5 }
+ */
+ static Fp2T g[gN];
+ static Fp2T g2[gN];
+ static Fp2T g3[gN];
+public:
+ static const Fp2T *get_gTbl() { return &g[0]; }
+ static const Fp2T *get_g2Tbl() { return &g2[0]; }
+ static const Fp2T *get_g3Tbl() { return &g3[0]; }
+ typedef typename Fp::BaseFp BaseFp;
+ static const size_t maxSize = Fp::maxSize * 2;
+ static inline size_t getByteSize() { return Fp::getByteSize() * 2; }
+ void dump() const
+ {
+ a.dump();
+ b.dump();
+ }
+ Fp a, b;
+ Fp2T() { }
+ Fp2T(int64_t a) : a(a), b(0) { }
+ Fp2T(const Fp& a, const Fp& b) : a(a), b(b) { }
+ Fp2T(int64_t a, int64_t b) : a(a), b(b) { }
+ Fp* getFp0() { return &a; }
+ const Fp* getFp0() const { return &a; }
+ const Unit* getUnit() const { return a.getUnit(); }
+ void clear()
+ {
+ a.clear();
+ b.clear();
+ }
+ void set(const Fp &a_, const Fp &b_)
+ {
+ a = a_;
+ b = b_;
+ }
+#ifdef MCL_XBYAK_DIRECT_CALL
+ static void (*add)(Fp2T& z, const Fp2T& x, const Fp2T& y);
+ static void (*sub)(Fp2T& z, const Fp2T& x, const Fp2T& y);
+ static void (*neg)(Fp2T& y, const Fp2T& x);
+ static void (*mul)(Fp2T& z, const Fp2T& x, const Fp2T& y);
+ static void (*sqr)(Fp2T& y, const Fp2T& x);
+#else
+ static void add(Fp2T& z, const Fp2T& x, const Fp2T& y) { addC(z, x, y); }
+ static void sub(Fp2T& z, const Fp2T& x, const Fp2T& y) { subC(z, x, y); }
+ static void neg(Fp2T& y, const Fp2T& x) { negC(y, x); }
+ static void mul(Fp2T& z, const Fp2T& x, const Fp2T& y) { mulC(z, x, y); }
+ static void sqr(Fp2T& y, const Fp2T& x) { sqrC(y, x); }
+#endif
+ static void (*mul_xi)(Fp2T& y, const Fp2T& x);
+ static void addPre(Fp2T& z, const Fp2T& x, const Fp2T& y) { Fp::addPre(z.a, x.a, y.a); Fp::addPre(z.b, x.b, y.b); }
+ static void inv(Fp2T& y, const Fp2T& x) { Fp::op_.fp2_inv(y.a.v_, x.a.v_); }
+ static void divBy2(Fp2T& y, const Fp2T& x)
+ {
+ Fp::divBy2(y.a, x.a);
+ Fp::divBy2(y.b, x.b);
+ }
+ static void divBy4(Fp2T& y, const Fp2T& x)
+ {
+ Fp::divBy4(y.a, x.a);
+ Fp::divBy4(y.b, x.b);
+ }
+ static void mulFp(Fp2T& z, const Fp2T& x, const Fp& y)
+ {
+ Fp::mul(z.a, x.a, y);
+ Fp::mul(z.b, x.b, y);
+ }
+ template<class S>
+ void setArray(bool *pb, const S *buf, size_t n)
+ {
+ assert((n & 1) == 0);
+ n /= 2;
+ a.setArray(pb, buf, n);
+ if (!*pb) return;
+ b.setArray(pb, buf + n, n);
+ }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode)
+ {
+ a.load(pb, is, ioMode);
+ if (!*pb) return;
+ b.load(pb, is, ioMode);
+ }
+ /*
+ Fp2T = <a> + ' ' + <b>
+ */
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ a.save(pb, os, ioMode);
+ if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ b.save(pb, os, ioMode);
+ }
+ bool isZero() const { return a.isZero() && b.isZero(); }
+ bool isOne() const { return a.isOne() && b.isZero(); }
+ bool operator==(const Fp2T& rhs) const { return a == rhs.a && b == rhs.b; }
+ bool operator!=(const Fp2T& rhs) const { return !operator==(rhs); }
+ /*
+ return true is a is odd (do not consider b)
+ this function is for only compressed reprezentation of EC
+ isOdd() is not good naming. QQQ
+ */
+ bool isOdd() const { return a.isOdd(); }
+ /*
+ (a + bi)^2 = (a^2 - b^2) + 2ab i = c + di
+ A = a^2
+ B = b^2
+ A = (c +/- sqrt(c^2 + d^2))/2
+ b = d / 2a
+ */
+ static inline bool squareRoot(Fp2T& y, const Fp2T& x)
+ {
+ Fp t1, t2;
+ if (x.b.isZero()) {
+ if (Fp::squareRoot(t1, x.a)) {
+ y.a = t1;
+ y.b.clear();
+ } else {
+ bool b = Fp::squareRoot(t1, -x.a);
+ assert(b); (void)b;
+ y.a.clear();
+ y.b = t1;
+ }
+ return true;
+ }
+ Fp::sqr(t1, x.a);
+ Fp::sqr(t2, x.b);
+ t1 += t2; // c^2 + d^2
+ if (!Fp::squareRoot(t1, t1)) return false;
+ Fp::add(t2, x.a, t1);
+ Fp::divBy2(t2, t2);
+ if (!Fp::squareRoot(t2, t2)) {
+ Fp::sub(t2, x.a, t1);
+ Fp::divBy2(t2, t2);
+ bool b = Fp::squareRoot(t2, t2);
+ assert(b); (void)b;
+ }
+ y.a = t2;
+ t2 += t2;
+ Fp::inv(t2, t2);
+ Fp::mul(y.b, x.b, t2);
+ return true;
+ }
+ static void inline norm(Fp& y, const Fp2T& x)
+ {
+ Fp aa, bb;
+ Fp::sqr(aa, x.a);
+ Fp::sqr(bb, x.b);
+ Fp::add(y, aa, bb);
+ }
+ /*
+ Frobenius
+ i^2 = -1
+ (a + bi)^p = a + bi^p in Fp
+ = a + bi if p = 1 mod 4
+ = a - bi if p = 3 mod 4
+ */
+ static void Frobenius(Fp2T& y, const Fp2T& x)
+ {
+ if (Fp::getOp().pmod4 == 1) {
+ if (&y != &x) {
+ y = x;
+ }
+ } else {
+ if (&y != &x) {
+ y.a = x.a;
+ }
+ Fp::neg(y.b, x.b);
+ }
+ }
+
+ static uint32_t get_xi_a() { return Fp::getOp().xi_a; }
+ static void init()
+ {
+// assert(Fp::maxSize <= 256);
+ mcl::fp::Op& op = Fp::op_;
+ assert(op.xi_a);
+ mul_xi = 0;
+#ifdef MCL_XBYAK_DIRECT_CALL
+ add = fp::func_ptr_cast<void (*)(Fp2T& z, const Fp2T& x, const Fp2T& y)>(op.fp2_addA_);
+ if (add == 0) add = addC;
+ sub = fp::func_ptr_cast<void (*)(Fp2T& z, const Fp2T& x, const Fp2T& y)>(op.fp2_subA_);
+ if (sub == 0) sub = subC;
+ neg = fp::func_ptr_cast<void (*)(Fp2T& y, const Fp2T& x)>(op.fp2_negA_);
+ if (neg == 0) neg = negC;
+ mul = fp::func_ptr_cast<void (*)(Fp2T& z, const Fp2T& x, const Fp2T& y)>(op.fp2_mulA_);
+ if (mul == 0) mul = mulC;
+ sqr = fp::func_ptr_cast<void (*)(Fp2T& y, const Fp2T& x)>(op.fp2_sqrA_);
+ if (sqr == 0) sqr = sqrC;
+ mul_xi = fp::func_ptr_cast<void (*)(Fp2T&, const Fp2T&)>(op.fp2_mul_xiA_);
+#endif
+ op.fp2_inv = fp2_invW;
+ if (mul_xi == 0) {
+ if (op.xi_a == 1) {
+ mul_xi = fp2_mul_xi_1_1iC;
+ } else {
+ mul_xi = fp2_mul_xiC;
+ }
+ }
+ FpDblT<Fp>::init();
+ Fp2DblT<Fp>::init();
+ // call init before Fp2::pow because FpDbl is used in Fp2T
+ const Fp2T xi(op.xi_a, 1);
+ const mpz_class& p = Fp::getOp().mp;
+ Fp2T::pow(g[0], xi, (p - 1) / 6); // g = xi^((p-1)/6)
+ for (size_t i = 1; i < gN; i++) {
+ g[i] = g[i - 1] * g[0];
+ }
+ /*
+ permutate [0, 1, 2, 3, 4] => [1, 3, 0, 2, 4]
+ g[0] = g^2
+ g[1] = g^4
+ g[2] = g^1
+ g[3] = g^3
+ g[4] = g^5
+ */
+ {
+ Fp2T t = g[0];
+ g[0] = g[1];
+ g[1] = g[3];
+ g[3] = g[2];
+ g[2] = t;
+ }
+ for (size_t i = 0; i < gN; i++) {
+ Fp2T t(g[i].a, g[i].b);
+ if (Fp::getOp().pmod4 == 3) Fp::neg(t.b, t.b);
+ Fp2T::mul(g2[i], t, g[i]);
+ g3[i] = g[i] * g2[i];
+ }
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("Fp2T:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("Fp2T:save");
+ }
+ template<class S>
+ void setArray(const S *buf, size_t n)
+ {
+ bool b;
+ setArray(&b, buf, n);
+ if (!b) throw cybozu::Exception("Fp2T:setArray");
+ }
+#endif
+#ifndef CYBOZU_DONT_USE_STRING
+ Fp2T(const std::string& a, const std::string& b, int base = 0) : a(a, base), b(b, base) {}
+ friend std::istream& operator>>(std::istream& is, Fp2T& self)
+ {
+ self.load(is, fp::detectIoMode(Fp::BaseFp::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const Fp2T& self)
+ {
+ self.save(os, fp::detectIoMode(Fp::BaseFp::getIoMode(), os));
+ return os;
+ }
+#endif
+private:
+ /*
+ default Fp2T operator
+ Fp2T = Fp[i]/(i^2 + 1)
+ */
+ static void addC(Fp2T& z, const Fp2T& x, const Fp2T& y)
+ {
+ Fp::add(z.a, x.a, y.a);
+ Fp::add(z.b, x.b, y.b);
+ }
+ static void subC(Fp2T& z, const Fp2T& x, const Fp2T& y)
+ {
+ Fp::sub(z.a, x.a, y.a);
+ Fp::sub(z.b, x.b, y.b);
+ }
+ static void negC(Fp2T& y, const Fp2T& x)
+ {
+ Fp::neg(y.a, x.a);
+ Fp::neg(y.b, x.b);
+ }
+#if 0
+ /*
+ x = a + bi, y = c + di, i^2 = -1
+ z = xy = (a + bi)(c + di) = (ac - bd) + (ad + bc)i
+ ad+bc = (a + b)(c + d) - ac - bd
+ # of mod = 3
+ */
+ static void fp2_mulW(Unit *z, const Unit *x, const Unit *y)
+ {
+ const Fp *px = reinterpret_cast<const Fp*>(x);
+ const Fp *py = reinterpret_cast<const Fp*>(y);
+ const Fp& a = px[0];
+ const Fp& b = px[1];
+ const Fp& c = py[0];
+ const Fp& d = py[1];
+ Fp *pz = reinterpret_cast<Fp*>(z);
+ Fp t1, t2, ac, bd;
+ Fp::add(t1, a, b);
+ Fp::add(t2, c, d);
+ t1 *= t2; // (a + b)(c + d)
+ Fp::mul(ac, a, c);
+ Fp::mul(bd, b, d);
+ Fp::sub(pz[0], ac, bd); // ac - bd
+ Fp::sub(pz[1], t1, ac);
+ pz[1] -= bd;
+ }
+ static void fp2_mulNFW(Fp2T& z, const Fp2T& x, const Fp2T& y)
+ {
+ const fp::Op& op = Fp::op_;
+ op.fp2_mulNF((Unit*)&z, (const Unit*)&x, (const Unit*)&y, op.p);
+ }
+#endif
+ static void mulC(Fp2T& z, const Fp2T& x, const Fp2T& y)
+ {
+ Fp2Dbl d;
+ Fp2Dbl::mulPre(d, x, y);
+ FpDbl::mod(z.a, d.a);
+ FpDbl::mod(z.b, d.b);
+ }
+ /*
+ x = a + bi, i^2 = -1
+ y = x^2 = (a + bi)^2 = (a + b)(a - b) + 2abi
+ */
+ static void sqrC(Fp2T& y, const Fp2T& x)
+ {
+ const Fp& a = x.a;
+ const Fp& b = x.b;
+#if 1 // faster than using FpDbl
+ Fp t1, t2, t3;
+ Fp::add(t1, b, b); // 2b
+ t1 *= a; // 2ab
+ Fp::add(t2, a, b); // a + b
+ Fp::sub(t3, a, b); // a - b
+ Fp::mul(y.a, t2, t3); // (a + b)(a - b)
+ y.b = t1;
+#else
+ Fp t1, t2;
+ FpDbl d1, d2;
+ Fp::addPre(t1, b, b); // 2b
+ FpDbl::mulPre(d2, t1, a); // 2ab
+ Fp::addPre(t1, a, b); // a + b
+ Fp::sub(t2, a, b); // a - b
+ FpDbl::mulPre(d1, t1, t2); // (a + b)(a - b)
+ FpDbl::mod(py[0], d1);
+ FpDbl::mod(py[1], d2);
+#endif
+ }
+ /*
+ xi = xi_a + i
+ x = a + bi
+ y = (a + bi)xi = (a + bi)(xi_a + i)
+ =(a * x_ia - b) + (a + b xi_a)i
+ */
+ static void fp2_mul_xiC(Fp2T& y, const Fp2T& x)
+ {
+ const Fp& a = x.a;
+ const Fp& b = x.b;
+ Fp t;
+ Fp::mulUnit(t, a, Fp::getOp().xi_a);
+ t -= b;
+ Fp::mulUnit(y.b, b, Fp::getOp().xi_a);
+ y.b += a;
+ y.a = t;
+ }
+ /*
+ xi = 1 + i ; xi_a = 1
+ y = (a + bi)xi = (a - b) + (a + b)i
+ */
+ static void fp2_mul_xi_1_1iC(Fp2T& y, const Fp2T& x)
+ {
+ const Fp& a = x.a;
+ const Fp& b = x.b;
+ Fp t;
+ Fp::add(t, a, b);
+ Fp::sub(y.a, a, b);
+ y.b = t;
+ }
+ /*
+ x = a + bi
+ 1 / x = (a - bi) / (a^2 + b^2)
+ */
+ static void fp2_invW(Unit *y, const Unit *x)
+ {
+ const Fp *px = reinterpret_cast<const Fp*>(x);
+ Fp *py = reinterpret_cast<Fp*>(y);
+ const Fp& a = px[0];
+ const Fp& b = px[1];
+ Fp aa, bb;
+ Fp::sqr(aa, a);
+ Fp::sqr(bb, b);
+ aa += bb;
+ Fp::inv(aa, aa); // aa = 1 / (a^2 + b^2)
+ Fp::mul(py[0], a, aa);
+ Fp::mul(py[1], b, aa);
+ Fp::neg(py[1], py[1]);
+ }
+};
+
+#ifdef MCL_XBYAK_DIRECT_CALL
+template<class Fp_> void (*Fp2T<Fp_>::add)(Fp2T& z, const Fp2T& x, const Fp2T& y);
+template<class Fp_> void (*Fp2T<Fp_>::sub)(Fp2T& z, const Fp2T& x, const Fp2T& y);
+template<class Fp_> void (*Fp2T<Fp_>::neg)(Fp2T& y, const Fp2T& x);
+template<class Fp_> void (*Fp2T<Fp_>::mul)(Fp2T& z, const Fp2T& x, const Fp2T& y);
+template<class Fp_> void (*Fp2T<Fp_>::sqr)(Fp2T& y, const Fp2T& x);
+#endif
+template<class Fp_> void (*Fp2T<Fp_>::mul_xi)(Fp2T& y, const Fp2T& x);
+
+template<class Fp>
+struct Fp2DblT {
+ typedef FpDblT<Fp> FpDbl;
+ typedef Fp2T<Fp> Fp2;
+ typedef fp::Unit Unit;
+ FpDbl a, b;
+ static void add(Fp2DblT& z, const Fp2DblT& x, const Fp2DblT& y)
+ {
+ FpDbl::add(z.a, x.a, y.a);
+ FpDbl::add(z.b, x.b, y.b);
+ }
+ static void addPre(Fp2DblT& z, const Fp2DblT& x, const Fp2DblT& y)
+ {
+ FpDbl::addPre(z.a, x.a, y.a);
+ FpDbl::addPre(z.b, x.b, y.b);
+ }
+ static void sub(Fp2DblT& z, const Fp2DblT& x, const Fp2DblT& y)
+ {
+ FpDbl::sub(z.a, x.a, y.a);
+ FpDbl::sub(z.b, x.b, y.b);
+ }
+ static void subPre(Fp2DblT& z, const Fp2DblT& x, const Fp2DblT& y)
+ {
+ FpDbl::subPre(z.a, x.a, y.a);
+ FpDbl::subPre(z.b, x.b, y.b);
+ }
+ static void neg(Fp2DblT& y, const Fp2DblT& x)
+ {
+ FpDbl::neg(y.a, x.a);
+ FpDbl::neg(y.b, x.b);
+ }
+ static void mul_xi(Fp2DblT& y, const Fp2DblT& x)
+ {
+ const uint32_t xi_a = Fp2::get_xi_a();
+ if (xi_a == 1) {
+ FpDbl t;
+ FpDbl::add(t, x.a, x.b);
+ FpDbl::sub(y.a, x.a, x.b);
+ y.b = t;
+ } else {
+ FpDbl t;
+ FpDbl::mulUnit(t, x.a, xi_a);
+ FpDbl::sub(t, t, x.b);
+ FpDbl::mulUnit(y.b, x.b, xi_a);
+ FpDbl::add(y.b, y.b, x.a);
+ y.a = t;
+ }
+ }
+ static void (*mulPre)(Fp2DblT&, const Fp2&, const Fp2&);
+ static void (*sqrPre)(Fp2DblT&, const Fp2&);
+ static void mod(Fp2& y, const Fp2DblT& x)
+ {
+ FpDbl::mod(y.a, x.a);
+ FpDbl::mod(y.b, x.b);
+ }
+#ifndef CYBOZU_DONT_USE_STRING
+ friend std::ostream& operator<<(std::ostream& os, const Fp2DblT& x)
+ {
+ return os << x.a << ' ' << x.b;
+ }
+#endif
+ void operator+=(const Fp2DblT& x) { add(*this, *this, x); }
+ void operator-=(const Fp2DblT& x) { sub(*this, *this, x); }
+ static void init()
+ {
+ const mcl::fp::Op& op = Fp::getOp();
+ if (op.fp2Dbl_mulPreA_) {
+ mulPre = fp::func_ptr_cast<void (*)(Fp2DblT&, const Fp2&, const Fp2&)>(op.fp2Dbl_mulPreA_);
+ } else {
+ if (op.isFullBit) {
+ mulPre = fp2Dbl_mulPreW<true>;
+ } else {
+ mulPre = fp2Dbl_mulPreW<false>;
+ }
+ }
+ if (op.fp2Dbl_sqrPreA_) {
+ sqrPre = fp::func_ptr_cast<void (*)(Fp2DblT&, const Fp2&)>(op.fp2Dbl_sqrPreA_);
+ } else {
+ if (op.isFullBit) {
+ sqrPre = fp2Dbl_sqrPreW<true>;
+ } else {
+ sqrPre = fp2Dbl_sqrPreW<false>;
+ }
+ }
+ }
+ /*
+ Fp2Dbl::mulPre by FpDblT
+ @note mod of NIST_P192 is fast
+ */
+ template<bool isFullBit>
+ static void fp2Dbl_mulPreW(Fp2DblT& z, const Fp2& x, const Fp2& y)
+ {
+ const Fp& a = x.a;
+ const Fp& b = x.b;
+ const Fp& c = y.a;
+ const Fp& d = y.b;
+ FpDbl& d0 = z.a;
+ FpDbl& d1 = z.b;
+ FpDbl d2;
+ Fp s, t;
+ if (isFullBit) {
+ Fp::add(s, a, b);
+ Fp::add(t, c, d);
+ } else {
+ Fp::addPre(s, a, b);
+ Fp::addPre(t, c, d);
+ }
+ FpDbl::mulPre(d1, s, t); // (a + b)(c + d)
+ FpDbl::mulPre(d0, a, c);
+ FpDbl::mulPre(d2, b, d);
+ if (isFullBit) {
+ FpDbl::sub(d1, d1, d0); // (a + b)(c + d) - ac
+ FpDbl::sub(d1, d1, d2); // (a + b)(c + d) - ac - bd
+ } else {
+ FpDbl::subPre(d1, d1, d0);
+ FpDbl::subPre(d1, d1, d2);
+ }
+ FpDbl::sub(d0, d0, d2); // ac - bd
+ }
+ template<bool isFullBit>
+ static void fp2Dbl_sqrPreW(Fp2DblT& y, const Fp2& x)
+ {
+ Fp t1, t2;
+ if (isFullBit) {
+ Fp::add(t1, x.b, x.b); // 2b
+ Fp::add(t2, x.a, x.b); // a + b
+ } else {
+ Fp::addPre(t1, x.b, x.b); // 2b
+ Fp::addPre(t2, x.a, x.b); // a + b
+ }
+ FpDbl::mulPre(y.b, t1, x.a); // 2ab
+ Fp::sub(t1, x.a, x.b); // a - b
+ FpDbl::mulPre(y.a, t1, t2); // (a + b)(a - b)
+ }
+};
+
+template<class Fp> void (*Fp2DblT<Fp>::mulPre)(Fp2DblT&, const Fp2T<Fp>&, const Fp2T<Fp>&);
+template<class Fp> void (*Fp2DblT<Fp>::sqrPre)(Fp2DblT&, const Fp2T<Fp>&);
+
+template<class Fp> Fp2T<Fp> Fp2T<Fp>::g[Fp2T<Fp>::gN];
+template<class Fp> Fp2T<Fp> Fp2T<Fp>::g2[Fp2T<Fp>::gN];
+template<class Fp> Fp2T<Fp> Fp2T<Fp>::g3[Fp2T<Fp>::gN];
+
+template<class Fp>
+struct Fp6DblT;
+/*
+ Fp6T = Fp2[v] / (v^3 - xi)
+ x = a + b v + c v^2
+*/
+template<class _Fp>
+struct Fp6T : public fp::Serializable<Fp6T<_Fp>,
+ fp::Operator<Fp6T<_Fp> > > {
+ typedef _Fp Fp;
+ typedef Fp2T<Fp> Fp2;
+ typedef Fp2DblT<Fp> Fp2Dbl;
+ typedef Fp6DblT<Fp> Fp6Dbl;
+ typedef Fp BaseFp;
+ Fp2 a, b, c;
+ Fp6T() { }
+ Fp6T(int64_t a) : a(a) , b(0) , c(0) { }
+ Fp6T(const Fp2& a, const Fp2& b, const Fp2& c) : a(a) , b(b) , c(c) { }
+ void clear()
+ {
+ a.clear();
+ b.clear();
+ c.clear();
+ }
+ Fp* getFp0() { return a.getFp0(); }
+ const Fp* getFp0() const { return a.getFp0(); }
+ Fp2* getFp2() { return &a; }
+ const Fp2* getFp2() const { return &a; }
+ void set(const Fp2 &a_, const Fp2 &b_, const Fp2 &c_)
+ {
+ a = a_;
+ b = b_;
+ c = c_;
+ }
+ bool isZero() const
+ {
+ return a.isZero() && b.isZero() && c.isZero();
+ }
+ bool isOne() const
+ {
+ return a.isOne() && b.isZero() && c.isZero();
+ }
+ bool operator==(const Fp6T& rhs) const
+ {
+ return a == rhs.a && b == rhs.b && c == rhs.c;
+ }
+ bool operator!=(const Fp6T& rhs) const { return !operator==(rhs); }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode)
+ {
+ a.load(pb, is, ioMode); if (!*pb) return;
+ b.load(pb, is, ioMode); if (!*pb) return;
+ c.load(pb, is, ioMode); if (!*pb) return;
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ a.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ b.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ c.save(pb, os, ioMode);
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("Fp6T:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("Fp6T:save");
+ }
+#endif
+#ifndef CYBOZU_DONT_USE_STRING
+ friend std::istream& operator>>(std::istream& is, Fp6T& self)
+ {
+ self.load(is, fp::detectIoMode(Fp::BaseFp::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const Fp6T& self)
+ {
+ self.save(os, fp::detectIoMode(Fp::BaseFp::getIoMode(), os));
+ return os;
+ }
+#endif
+ static void add(Fp6T& z, const Fp6T& x, const Fp6T& y)
+ {
+ Fp2::add(z.a, x.a, y.a);
+ Fp2::add(z.b, x.b, y.b);
+ Fp2::add(z.c, x.c, y.c);
+ }
+ static void sub(Fp6T& z, const Fp6T& x, const Fp6T& y)
+ {
+ Fp2::sub(z.a, x.a, y.a);
+ Fp2::sub(z.b, x.b, y.b);
+ Fp2::sub(z.c, x.c, y.c);
+ }
+ static void neg(Fp6T& y, const Fp6T& x)
+ {
+ Fp2::neg(y.a, x.a);
+ Fp2::neg(y.b, x.b);
+ Fp2::neg(y.c, x.c);
+ }
+ /*
+ x = a + bv + cv^2, v^3 = xi
+ x^2 = (a^2 + 2bc xi) + (c^2 xi + 2ab)v + (b^2 + 2ac)v^2
+
+ b^2 + 2ac = (a + b + c)^2 - a^2 - 2bc - c^2 - 2ab
+ */
+ static void sqr(Fp6T& y, const Fp6T& x)
+ {
+ Fp2 t1, t2, t3;
+ Fp2::mul(t1, x.a, x.b);
+ t1 += t1; // 2ab
+ Fp2::mul(t2, x.b, x.c);
+ t2 += t2; // 2bc
+ Fp2::sqr(t3, x.c); // c^2
+ Fp2::add(y.c, x.a, x.c); // a + c, destroy y.c
+ y.c += x.b; // a + b + c
+ Fp2::sqr(y.b, y.c); // (a + b + c)^2, destroy y.b
+ y.b -= t2; // (a + b + c)^2 - 2bc
+ Fp2::mul_xi(t2, t2); // 2bc xi
+ Fp2::sqr(y.a, x.a); // a^2, destroy y.a
+ y.b -= y.a; // (a + b + c)^2 - 2bc - a^2
+ y.a += t2; // a^2 + 2bc xi
+ Fp2::sub(y.c, y.b, t3); // (a + b + c)^2 - 2bc - a^2 - c^2
+ Fp2::mul_xi(y.b, t3); // c^2 xi
+ y.b += t1; // c^2 xi + 2ab
+ y.c -= t1; // b^2 + 2ac
+ }
+ static inline void mul(Fp6T& z, const Fp6T& x, const Fp6T& y);
+ /*
+ x = a + bv + cv^2, v^3 = xi
+ y = 1/x = p/q where
+ p = (a^2 - bc xi) + (c^2 xi - ab)v + (b^2 - ac)v^2
+ q = c^3 xi^2 + b(b^2 - 3ac)xi + a^3
+ = (a^2 - bc xi)a + ((c^2 xi - ab)c + (b^2 - ac)b) xi
+ */
+ static void inv(Fp6T& y, const Fp6T& x)
+ {
+ const Fp2& a = x.a;
+ const Fp2& b = x.b;
+ const Fp2& c = x.c;
+ Fp2 aa, bb, cc, ab, bc, ac;
+ Fp2::sqr(aa, a);
+ Fp2::sqr(bb, b);
+ Fp2::sqr(cc, c);
+ Fp2::mul(ab, a, b);
+ Fp2::mul(bc, b, c);
+ Fp2::mul(ac, c, a);
+
+ Fp6T p;
+ Fp2::mul_xi(p.a, bc);
+ Fp2::sub(p.a, aa, p.a); // a^2 - bc xi
+ Fp2::mul_xi(p.b, cc);
+ p.b -= ab; // c^2 xi - ab
+ Fp2::sub(p.c, bb, ac); // b^2 - ac
+ Fp2 q, t;
+ Fp2::mul(q, p.b, c);
+ Fp2::mul(t, p.c, b);
+ q += t;
+ Fp2::mul_xi(q, q);
+ Fp2::mul(t, p.a, a);
+ q += t;
+ Fp2::inv(q, q);
+
+ Fp2::mul(y.a, p.a, q);
+ Fp2::mul(y.b, p.b, q);
+ Fp2::mul(y.c, p.c, q);
+ }
+};
+
+template<class Fp>
+struct Fp6DblT {
+ typedef Fp2T<Fp> Fp2;
+ typedef Fp6T<Fp> Fp6;
+ typedef Fp2DblT<Fp> Fp2Dbl;
+ typedef Fp6DblT<Fp> Fp6Dbl;
+ typedef fp::Unit Unit;
+ Fp2Dbl a, b, c;
+ static void add(Fp6Dbl& z, const Fp6Dbl& x, const Fp6Dbl& y)
+ {
+ Fp2Dbl::add(z.a, x.a, y.a);
+ Fp2Dbl::add(z.b, x.b, y.b);
+ Fp2Dbl::add(z.c, x.c, y.c);
+ }
+ static void sub(Fp6Dbl& z, const Fp6Dbl& x, const Fp6Dbl& y)
+ {
+ Fp2Dbl::sub(z.a, x.a, y.a);
+ Fp2Dbl::sub(z.b, x.b, y.b);
+ Fp2Dbl::sub(z.c, x.c, y.c);
+ }
+ /*
+ x = a + bv + cv^2, y = d + ev + fv^2, v^3 = xi
+ xy = (ad + (bf + ce)xi) + ((ae + bd) + cf xi)v + ((af + cd) + be)v^2
+ bf + ce = (b + c)(e + f) - be - cf
+ ae + bd = (a + b)(e + d) - ad - be
+ af + cd = (a + c)(d + f) - ad - cf
+ */
+ static void mulPre(Fp6DblT& z, const Fp6& x, const Fp6& y)
+ {
+//clk.begin();
+ const Fp2& a = x.a;
+ const Fp2& b = x.b;
+ const Fp2& c = x.c;
+ const Fp2& d = y.a;
+ const Fp2& e = y.b;
+ const Fp2& f = y.c;
+ Fp2Dbl& za = z.a;
+ Fp2Dbl& zb = z.b;
+ Fp2Dbl& zc = z.c;
+ Fp2Dbl BE;
+ Fp2Dbl::mulPre(za, a, d);
+ Fp2Dbl::mulPre(BE, b, e);
+ Fp2Dbl::mulPre(zb, c, f);
+
+ Fp2 t1, t2, t3, t4;
+ Fp2::add(t1, b, c);
+ Fp2::add(t2, e, f);
+ Fp2Dbl T1;
+ Fp2Dbl::mulPre(T1, t1, t2);
+ Fp2Dbl::sub(T1, T1, BE);
+ Fp2Dbl::sub(T1, T1, zb);
+ Fp2Dbl::mul_xi(T1, T1);
+
+ Fp2::add(t2, a, b);
+ Fp2::add(t3, e, d);
+ Fp2Dbl T2;
+ Fp2Dbl::mulPre(T2, t2, t3);
+ Fp2Dbl::sub(T2, T2, za);
+ Fp2Dbl::sub(T2, T2, BE);
+
+ Fp2::add(t3, a, c);
+ Fp2::add(t4, d, f);
+ Fp2Dbl::mulPre(zc, t3, t4);
+ Fp2Dbl::sub(zc, zc, za);
+ Fp2Dbl::sub(zc, zc, zb);
+
+ Fp2Dbl::add(za, za, T1);
+ Fp2Dbl::mul_xi(zb, zb);
+ Fp2Dbl::add(zb, zb, T2);
+ Fp2Dbl::add(zc, zc, BE);
+//clk.end();
+ }
+ static void mod(Fp6& y, const Fp6Dbl& x)
+ {
+ Fp2Dbl::mod(y.a, x.a);
+ Fp2Dbl::mod(y.b, x.b);
+ Fp2Dbl::mod(y.c, x.c);
+ }
+};
+
+template<class Fp>
+inline void Fp6T<Fp>::mul(Fp6T<Fp>& z, const Fp6T<Fp>& x, const Fp6T<Fp>& y)
+{
+ Fp6DblT<Fp> Z;
+ Fp6DblT<Fp>::mulPre(Z, x, y);
+ Fp6DblT<Fp>::mod(z, Z);
+}
+
+/*
+ Fp12T = Fp6[w] / (w^2 - v)
+ x = a + b w
+*/
+template<class Fp>
+struct Fp12T : public fp::Serializable<Fp12T<Fp>,
+ fp::Operator<Fp12T<Fp> > > {
+ typedef Fp2T<Fp> Fp2;
+ typedef Fp6T<Fp> Fp6;
+ typedef Fp2DblT<Fp> Fp2Dbl;
+ typedef Fp6DblT<Fp> Fp6Dbl;
+ typedef Fp BaseFp;
+ Fp6 a, b;
+ Fp12T() {}
+ Fp12T(int64_t a) : a(a), b(0) {}
+ Fp12T(const Fp6& a, const Fp6& b) : a(a), b(b) {}
+ void clear()
+ {
+ a.clear();
+ b.clear();
+ }
+ void setOne()
+ {
+ clear();
+ a.a.a = 1;
+ }
+
+ Fp* getFp0() { return a.getFp0(); }
+ const Fp* getFp0() const { return a.getFp0(); }
+ Fp2* getFp2() { return a.getFp2(); }
+ const Fp2* getFp2() const { return a.getFp2(); }
+ void set(const Fp2& v0, const Fp2& v1, const Fp2& v2, const Fp2& v3, const Fp2& v4, const Fp2& v5)
+ {
+ a.set(v0, v1, v2);
+ b.set(v3, v4, v5);
+ }
+
+ bool isZero() const
+ {
+ return a.isZero() && b.isZero();
+ }
+ bool isOne() const
+ {
+ return a.isOne() && b.isZero();
+ }
+ bool operator==(const Fp12T& rhs) const
+ {
+ return a == rhs.a && b == rhs.b;
+ }
+ bool operator!=(const Fp12T& rhs) const { return !operator==(rhs); }
+ static void add(Fp12T& z, const Fp12T& x, const Fp12T& y)
+ {
+ Fp6::add(z.a, x.a, y.a);
+ Fp6::add(z.b, x.b, y.b);
+ }
+ static void sub(Fp12T& z, const Fp12T& x, const Fp12T& y)
+ {
+ Fp6::sub(z.a, x.a, y.a);
+ Fp6::sub(z.b, x.b, y.b);
+ }
+ static void neg(Fp12T& z, const Fp12T& x)
+ {
+ Fp6::neg(z.a, x.a);
+ Fp6::neg(z.b, x.b);
+ }
+ /*
+ z = x v + y
+ in Fp6 : (a + bv + cv^2)v = cv^3 + av + bv^2 = cxi + av + bv^2
+ */
+ static void mulVadd(Fp6& z, const Fp6& x, const Fp6& y)
+ {
+ Fp2 t;
+ Fp2::mul_xi(t, x.c);
+ Fp2::add(z.c, x.b, y.c);
+ Fp2::add(z.b, x.a, y.b);
+ Fp2::add(z.a, t, y.a);
+ }
+ static void mulVadd(Fp6Dbl& z, const Fp6Dbl& x, const Fp6Dbl& y)
+ {
+ Fp2Dbl t;
+ Fp2Dbl::mul_xi(t, x.c);
+ Fp2Dbl::add(z.c, x.b, y.c);
+ Fp2Dbl::add(z.b, x.a, y.b);
+ Fp2Dbl::add(z.a, t, y.a);
+ }
+ /*
+ x = a + bw, y = c + dw, w^2 = v
+ z = xy = (a + bw)(c + dw) = (ac + bdv) + (ad + bc)w
+ ad+bc = (a + b)(c + d) - ac - bd
+
+ in Fp6 : (a + bv + cv^2)v = cv^3 + av + bv^2 = cxi + av + bv^2
+ */
+ static void mul(Fp12T& z, const Fp12T& x, const Fp12T& y)
+ {
+ // 4.7Kclk -> 4.55Kclk
+ const Fp6& a = x.a;
+ const Fp6& b = x.b;
+ const Fp6& c = y.a;
+ const Fp6& d = y.b;
+ Fp6 t1, t2;
+ Fp6::add(t1, a, b);
+ Fp6::add(t2, c, d);
+#if 1
+ Fp6Dbl T, AC, BD;
+ Fp6Dbl::mulPre(AC, a, c);
+ Fp6Dbl::mulPre(BD, b, d);
+ mulVadd(T, BD, AC);
+ Fp6Dbl::mod(z.a, T);
+ Fp6Dbl::mulPre(T, t1, t2); // (a + b)(c + d)
+ Fp6Dbl::sub(T, T, AC);
+ Fp6Dbl::sub(T, T, BD);
+ Fp6Dbl::mod(z.b, T);
+#else
+ Fp6 ac, bd;
+ t1 *= t2; // (a + b)(c + d)
+ Fp6::mul(ac, a, c);
+ Fp6::mul(bd, b, d);
+ mulVadd(z.a, bd, ac);
+ t1 -= ac;
+ Fp6::sub(z.b, t1, bd);
+#endif
+ }
+ /*
+ x = a + bw, w^2 = v
+ y = x^2 = (a + bw)^2 = (a^2 + b^2v) + 2abw
+ a^2 + b^2v = (a + b)(bv + a) - (abv + ab)
+ */
+ static void sqr(Fp12T& y, const Fp12T& x)
+ {
+ const Fp6& a = x.a;
+ const Fp6& b = x.b;
+ Fp6 t0, t1;
+ Fp6::add(t0, a, b); // a + b
+ mulVadd(t1, b, a); // bv + a
+ t0 *= t1; // (a + b)(bv + a)
+ Fp6::mul(t1, a, b); // ab
+ Fp6::add(y.b, t1, t1); // 2ab
+ mulVadd(y.a, t1, t1); // abv + ab
+ Fp6::sub(y.a, t0, y.a);
+ }
+ /*
+ x = a + bw, w^2 = v
+ y = 1/x = (a - bw) / (a^2 - b^2v)
+ */
+ static void inv(Fp12T& y, const Fp12T& x)
+ {
+ const Fp6& a = x.a;
+ const Fp6& b = x.b;
+ Fp6 t0, t1;
+ Fp6::sqr(t0, a);
+ Fp6::sqr(t1, b);
+ Fp2::mul_xi(t1.c, t1.c);
+ t0.a -= t1.c;
+ t0.b -= t1.a;
+ t0.c -= t1.b; // t0 = a^2 - b^2v
+ Fp6::inv(t0, t0);
+ Fp6::mul(y.a, x.a, t0);
+ Fp6::mul(y.b, x.b, t0);
+ Fp6::neg(y.b, y.b);
+ }
+ /*
+ y = 1 / x = conjugate of x if |x| = 1
+ */
+ static void unitaryInv(Fp12T& y, const Fp12T& x)
+ {
+ if (&y != &x) y.a = x.a;
+ Fp6::neg(y.b, x.b);
+ }
+ /*
+ Frobenius
+ i^2 = -1
+ (a + bi)^p = a + bi^p in Fp
+ = a + bi if p = 1 mod 4
+ = a - bi if p = 3 mod 4
+
+ g = xi^(p - 1) / 6
+ v^3 = xi in Fp2
+ v^p = ((v^6) ^ (p-1)/6) v = g^2 v
+ v^2p = g^4 v^2
+ (a + bv + cv^2)^p in Fp6
+ = F(a) + F(b)g^2 v + F(c) g^4 v^2
+
+ w^p = ((w^6) ^ (p-1)/6) w = g w
+ ((a + bv + cv^2)w)^p in Fp12T
+ = (F(a) g + F(b) g^3 v + F(c) g^5 v^2)w
+ */
+ static void Frobenius(Fp12T& y, const Fp12T& x)
+ {
+ for (int i = 0; i < 6; i++) {
+ Fp2::Frobenius(y.getFp2()[i], x.getFp2()[i]);
+ }
+ for (int i = 1; i < 6; i++) {
+ y.getFp2()[i] *= Fp2::get_gTbl()[i - 1];
+ }
+ }
+ static void Frobenius2(Fp12T& y, const Fp12T& x)
+ {
+#if 0
+ Frobenius(y, x);
+ Frobenius(y, y);
+#else
+ y.getFp2()[0] = x.getFp2()[0];
+ if (Fp::getOp().pmod4 == 1) {
+ for (int i = 1; i < 6; i++) {
+ Fp2::mul(y.getFp2()[i], x.getFp2()[i], Fp2::get_g2Tbl()[i]);
+ }
+ } else {
+ for (int i = 1; i < 6; i++) {
+ Fp2::mulFp(y.getFp2()[i], x.getFp2()[i], Fp2::get_g2Tbl()[i - 1].a);
+ }
+ }
+#endif
+ }
+ static void Frobenius3(Fp12T& y, const Fp12T& x)
+ {
+#if 0
+ Frobenius(y, x);
+ Frobenius(y, y);
+ Frobenius(y, y);
+#else
+ Fp2::Frobenius(y.getFp2()[0], x.getFp2()[0]);
+ for (int i = 1; i < 6; i++) {
+ Fp2::Frobenius(y.getFp2()[i], x.getFp2()[i]);
+ y.getFp2()[i] *= Fp2::get_g3Tbl()[i - 1];
+ }
+#endif
+ }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode)
+ {
+ a.load(pb, is, ioMode); if (!*pb) return;
+ b.load(pb, is, ioMode);
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ a.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ b.save(pb, os, ioMode);
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("Fp12T:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("Fp12T:save");
+ }
+#endif
+#ifndef CYBOZU_DONT_USE_STRING
+ friend std::istream& operator>>(std::istream& is, Fp12T& self)
+ {
+ self.load(is, fp::detectIoMode(Fp::BaseFp::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const Fp12T& self)
+ {
+ self.save(os, fp::detectIoMode(Fp::BaseFp::getIoMode(), os));
+ return os;
+ }
+#endif
+};
+
+/*
+ convert multiplicative group to additive group
+*/
+template<class T>
+struct GroupMtoA : public T {
+ static T& castT(GroupMtoA& x) { return static_cast<T&>(x); }
+ static const T& castT(const GroupMtoA& x) { return static_cast<const T&>(x); }
+ void clear()
+ {
+ castT(*this) = 1;
+ }
+ bool isZero() const { return castT(*this).isOne(); }
+ static void add(GroupMtoA& z, const GroupMtoA& x, const GroupMtoA& y)
+ {
+ T::mul(castT(z), castT(x), castT(y));
+ }
+ static void dbl(GroupMtoA& y, const GroupMtoA& x)
+ {
+ T::sqr(castT(y), castT(x));
+ }
+ static void neg(GroupMtoA& y, const GroupMtoA& x)
+ {
+ // assume Fp12
+ T::unitaryInv(castT(y), castT(x));
+ }
+ static void Frobenus(GroupMtoA& y, const GroupMtoA& x)
+ {
+ T::Frobenius(castT(y), castT(x));
+ }
+ template<class INT>
+ static void mul(GroupMtoA& z, const GroupMtoA& x, const INT& y)
+ {
+ T::pow(castT(z), castT(x), y);
+ }
+ template<class INT>
+ static void mulGeneric(GroupMtoA& z, const GroupMtoA& x, const INT& y)
+ {
+ T::powGeneric(castT(z), castT(x), y);
+ }
+ void operator+=(const GroupMtoA& rhs)
+ {
+ add(*this, *this, rhs);
+ }
+ void normalize() {}
+private:
+ bool isOne() const;
+};
+
+} // mcl
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/gmp_util.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/gmp_util.hpp
new file mode 100644
index 000000000..bcbd91a1e
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/gmp_util.hpp
@@ -0,0 +1,954 @@
+#pragma once
+/**
+ @file
+ @brief util function for gmp
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdint.h>
+#include <cybozu/exception.hpp>
+#include <mcl/randgen.hpp>
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable : 4616)
+ #pragma warning(disable : 4800)
+ #pragma warning(disable : 4244)
+ #pragma warning(disable : 4127)
+ #pragma warning(disable : 4512)
+ #pragma warning(disable : 4146)
+#endif
+#if defined(__EMSCRIPTEN__) || defined(__wasm__)
+ #define MCL_USE_VINT
+#endif
+#ifdef MCL_USE_VINT
+#include <mcl/vint.hpp>
+typedef mcl::Vint mpz_class;
+#else
+#include <gmpxx.h>
+#ifdef _MSC_VER
+ #pragma warning(pop)
+ #include <cybozu/link_mpir.hpp>
+#endif
+#endif
+
+#ifndef MCL_SIZEOF_UNIT
+ #if defined(CYBOZU_OS_BIT) && (CYBOZU_OS_BIT == 32)
+ #define MCL_SIZEOF_UNIT 4
+ #else
+ #define MCL_SIZEOF_UNIT 8
+ #endif
+#endif
+
+namespace mcl {
+
+namespace fp {
+
+#if MCL_SIZEOF_UNIT == 8
+typedef uint64_t Unit;
+#else
+typedef uint32_t Unit;
+#endif
+#define MCL_UNIT_BIT_SIZE (MCL_SIZEOF_UNIT * 8)
+
+} // mcl::fp
+
+namespace gmp {
+
+typedef mpz_class ImplType;
+
+// z = [buf[n-1]:..:buf[1]:buf[0]]
+// eg. buf[] = {0x12345678, 0xaabbccdd}; => z = 0xaabbccdd12345678;
+template<class T>
+void setArray(bool *pb, mpz_class& z, const T *buf, size_t n)
+{
+#ifdef MCL_USE_VINT
+ z.setArray(pb, buf, n);
+#else
+ mpz_import(z.get_mpz_t(), n, -1, sizeof(*buf), 0, 0, buf);
+ *pb = true;
+#endif
+}
+/*
+ buf[0, size) = x
+ buf[size, maxSize) with zero
+*/
+template<class T, class U>
+bool getArray_(T *buf, size_t maxSize, const U *x, int xn)//const mpz_srcptr x)
+{
+ const size_t bufByteSize = sizeof(T) * maxSize;
+ if (xn < 0) return false;
+ size_t xByteSize = sizeof(*x) * xn;
+ if (xByteSize > bufByteSize) return false;
+ memcpy(buf, x, xByteSize);
+ memset((char*)buf + xByteSize, 0, bufByteSize - xByteSize);
+ return true;
+}
+template<class T>
+void getArray(bool *pb, T *buf, size_t maxSize, const mpz_class& x)
+{
+#ifdef MCL_USE_VINT
+ *pb = getArray_(buf, maxSize, x.getUnit(), x.getUnitSize());
+#else
+ *pb = getArray_(buf, maxSize, x.get_mpz_t()->_mp_d, x.get_mpz_t()->_mp_size);
+#endif
+}
+inline void set(mpz_class& z, uint64_t x)
+{
+ bool b;
+ setArray(&b, z, &x, 1);
+ assert(b);
+ (void)b;
+}
+inline void setStr(bool *pb, mpz_class& z, const char *str, int base = 0)
+{
+#ifdef MCL_USE_VINT
+ z.setStr(pb, str, base);
+#else
+ *pb = z.set_str(str, base) == 0;
+#endif
+}
+
+/*
+ set buf with string terminated by '\0'
+ return strlen(buf) if success else 0
+*/
+inline size_t getStr(char *buf, size_t bufSize, const mpz_class& z, int base = 10)
+{
+#ifdef MCL_USE_VINT
+ return z.getStr(buf, bufSize, base);
+#else
+ __gmp_alloc_cstring tmp(mpz_get_str(0, base, z.get_mpz_t()));
+ size_t n = strlen(tmp.str);
+ if (n + 1 > bufSize) return 0;
+ memcpy(buf, tmp.str, n + 1);
+ return n;
+#endif
+}
+
+#ifndef CYBOZU_DONT_USE_STRING
+inline void getStr(std::string& str, const mpz_class& z, int base = 10)
+{
+#ifdef MCL_USE_VINT
+ z.getStr(str, base);
+#else
+ str = z.get_str(base);
+#endif
+}
+inline std::string getStr(const mpz_class& z, int base = 10)
+{
+ std::string s;
+ gmp::getStr(s, z, base);
+ return s;
+}
+#endif
+
+inline void add(mpz_class& z, const mpz_class& x, const mpz_class& y)
+{
+#ifdef MCL_USE_VINT
+ Vint::add(z, x, y);
+#else
+ mpz_add(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
+#endif
+}
+#ifndef MCL_USE_VINT
+inline void add(mpz_class& z, const mpz_class& x, unsigned int y)
+{
+ mpz_add_ui(z.get_mpz_t(), x.get_mpz_t(), y);
+}
+inline void sub(mpz_class& z, const mpz_class& x, unsigned int y)
+{
+ mpz_sub_ui(z.get_mpz_t(), x.get_mpz_t(), y);
+}
+inline void mul(mpz_class& z, const mpz_class& x, unsigned int y)
+{
+ mpz_mul_ui(z.get_mpz_t(), x.get_mpz_t(), y);
+}
+inline void div(mpz_class& q, const mpz_class& x, unsigned int y)
+{
+ mpz_div_ui(q.get_mpz_t(), x.get_mpz_t(), y);
+}
+inline void mod(mpz_class& r, const mpz_class& x, unsigned int m)
+{
+ mpz_mod_ui(r.get_mpz_t(), x.get_mpz_t(), m);
+}
+inline int compare(const mpz_class& x, int y)
+{
+ return mpz_cmp_si(x.get_mpz_t(), y);
+}
+#endif
+inline void sub(mpz_class& z, const mpz_class& x, const mpz_class& y)
+{
+#ifdef MCL_USE_VINT
+ Vint::sub(z, x, y);
+#else
+ mpz_sub(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
+#endif
+}
+inline void mul(mpz_class& z, const mpz_class& x, const mpz_class& y)
+{
+#ifdef MCL_USE_VINT
+ Vint::mul(z, x, y);
+#else
+ mpz_mul(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
+#endif
+}
+inline void sqr(mpz_class& z, const mpz_class& x)
+{
+#ifdef MCL_USE_VINT
+ Vint::mul(z, x, x);
+#else
+ mpz_mul(z.get_mpz_t(), x.get_mpz_t(), x.get_mpz_t());
+#endif
+}
+inline void divmod(mpz_class& q, mpz_class& r, const mpz_class& x, const mpz_class& y)
+{
+#ifdef MCL_USE_VINT
+ Vint::divMod(&q, r, x, y);
+#else
+ mpz_divmod(q.get_mpz_t(), r.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
+#endif
+}
+inline void div(mpz_class& q, const mpz_class& x, const mpz_class& y)
+{
+#ifdef MCL_USE_VINT
+ Vint::div(q, x, y);
+#else
+ mpz_div(q.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
+#endif
+}
+inline void mod(mpz_class& r, const mpz_class& x, const mpz_class& m)
+{
+#ifdef MCL_USE_VINT
+ Vint::mod(r, x, m);
+#else
+ mpz_mod(r.get_mpz_t(), x.get_mpz_t(), m.get_mpz_t());
+#endif
+}
+inline void clear(mpz_class& z)
+{
+#ifdef MCL_USE_VINT
+ z.clear();
+#else
+ mpz_set_ui(z.get_mpz_t(), 0);
+#endif
+}
+inline bool isZero(const mpz_class& z)
+{
+#ifdef MCL_USE_VINT
+ return z.isZero();
+#else
+ return mpz_sgn(z.get_mpz_t()) == 0;
+#endif
+}
+inline bool isNegative(const mpz_class& z)
+{
+#ifdef MCL_USE_VINT
+ return z.isNegative();
+#else
+ return mpz_sgn(z.get_mpz_t()) < 0;
+#endif
+}
+inline void neg(mpz_class& z, const mpz_class& x)
+{
+#ifdef MCL_USE_VINT
+ Vint::neg(z, x);
+#else
+ mpz_neg(z.get_mpz_t(), x.get_mpz_t());
+#endif
+}
+inline int compare(const mpz_class& x, const mpz_class & y)
+{
+#ifdef MCL_USE_VINT
+ return Vint::compare(x, y);
+#else
+ return mpz_cmp(x.get_mpz_t(), y.get_mpz_t());
+#endif
+}
+template<class T>
+void addMod(mpz_class& z, const mpz_class& x, const T& y, const mpz_class& m)
+{
+ add(z, x, y);
+ if (compare(z, m) >= 0) {
+ sub(z, z, m);
+ }
+}
+template<class T>
+void subMod(mpz_class& z, const mpz_class& x, const T& y, const mpz_class& m)
+{
+ sub(z, x, y);
+ if (!isNegative(z)) return;
+ add(z, z, m);
+}
+template<class T>
+void mulMod(mpz_class& z, const mpz_class& x, const T& y, const mpz_class& m)
+{
+ mul(z, x, y);
+ mod(z, z, m);
+}
+inline void sqrMod(mpz_class& z, const mpz_class& x, const mpz_class& m)
+{
+ sqr(z, x);
+ mod(z, z, m);
+}
+// z = x^y (y >= 0)
+inline void pow(mpz_class& z, const mpz_class& x, unsigned int y)
+{
+#ifdef MCL_USE_VINT
+ Vint::pow(z, x, y);
+#else
+ mpz_pow_ui(z.get_mpz_t(), x.get_mpz_t(), y);
+#endif
+}
+// z = x^y mod m (y >=0)
+inline void powMod(mpz_class& z, const mpz_class& x, const mpz_class& y, const mpz_class& m)
+{
+#ifdef MCL_USE_VINT
+ Vint::powMod(z, x, y, m);
+#else
+ mpz_powm(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t(), m.get_mpz_t());
+#endif
+}
+// z = 1/x mod m
+inline void invMod(mpz_class& z, const mpz_class& x, const mpz_class& m)
+{
+#ifdef MCL_USE_VINT
+ Vint::invMod(z, x, m);
+#else
+ mpz_invert(z.get_mpz_t(), x.get_mpz_t(), m.get_mpz_t());
+#endif
+}
+// z = lcm(x, y)
+inline void lcm(mpz_class& z, const mpz_class& x, const mpz_class& y)
+{
+#ifdef MCL_USE_VINT
+ Vint::lcm(z, x, y);
+#else
+ mpz_lcm(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
+#endif
+}
+inline mpz_class lcm(const mpz_class& x, const mpz_class& y)
+{
+ mpz_class z;
+ lcm(z, x, y);
+ return z;
+}
+// z = gcd(x, y)
+inline void gcd(mpz_class& z, const mpz_class& x, const mpz_class& y)
+{
+#ifdef MCL_USE_VINT
+ Vint::gcd(z, x, y);
+#else
+ mpz_gcd(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
+#endif
+}
+inline mpz_class gcd(const mpz_class& x, const mpz_class& y)
+{
+ mpz_class z;
+ gcd(z, x, y);
+ return z;
+}
+/*
+ assume p : odd prime
+ return 1 if x^2 = a mod p for some x
+ return -1 if x^2 != a mod p for any x
+*/
+inline int legendre(const mpz_class& a, const mpz_class& p)
+{
+#ifdef MCL_USE_VINT
+ return Vint::jacobi(a, p);
+#else
+ return mpz_legendre(a.get_mpz_t(), p.get_mpz_t());
+#endif
+}
+inline bool isPrime(bool *pb, const mpz_class& x)
+{
+#ifdef MCL_USE_VINT
+ return x.isPrime(pb, 32);
+#else
+ *pb = true;
+ return mpz_probab_prime_p(x.get_mpz_t(), 32) != 0;
+#endif
+}
+inline size_t getBitSize(const mpz_class& x)
+{
+#ifdef MCL_USE_VINT
+ return x.getBitSize();
+#else
+ return mpz_sizeinbase(x.get_mpz_t(), 2);
+#endif
+}
+inline bool testBit(const mpz_class& x, size_t pos)
+{
+#ifdef MCL_USE_VINT
+ return x.testBit(pos);
+#else
+ return mpz_tstbit(x.get_mpz_t(), pos) != 0;
+#endif
+}
+inline void resetBit(mpz_class& x, size_t pos)
+{
+#ifdef MCL_USE_VINT
+ x.setBit(pos, false);
+#else
+ mpz_clrbit(x.get_mpz_t(), pos);
+#endif
+}
+inline void setBit(mpz_class& x, size_t pos, bool v = true)
+{
+#ifdef MCL_USE_VINT
+ x.setBit(pos, v);
+#else
+ if (v) {
+ mpz_setbit(x.get_mpz_t(), pos);
+ } else {
+ resetBit(x, pos);
+ }
+#endif
+}
+inline const fp::Unit *getUnit(const mpz_class& x)
+{
+#ifdef MCL_USE_VINT
+ return x.getUnit();
+#else
+ return reinterpret_cast<const fp::Unit*>(x.get_mpz_t()->_mp_d);
+#endif
+}
+inline fp::Unit getUnit(const mpz_class& x, size_t i)
+{
+ return getUnit(x)[i];
+}
+inline size_t getUnitSize(const mpz_class& x)
+{
+#ifdef MCL_USE_VINT
+ return x.getUnitSize();
+#else
+ return std::abs(x.get_mpz_t()->_mp_size);
+#endif
+}
+inline mpz_class abs(const mpz_class& x)
+{
+#ifdef MCL_USE_VINT
+ return Vint::abs(x);
+#else
+ return ::abs(x);
+#endif
+}
+
+inline void getRand(bool *pb, mpz_class& z, size_t bitSize, fp::RandGen rg = fp::RandGen())
+{
+ if (rg.isZero()) rg = fp::RandGen::get();
+ assert(bitSize > 1);
+ const size_t rem = bitSize & 31;
+ const size_t n = (bitSize + 31) / 32;
+ uint32_t buf[128];
+ assert(n <= CYBOZU_NUM_OF_ARRAY(buf));
+ if (n > CYBOZU_NUM_OF_ARRAY(buf)) {
+ *pb = false;
+ return;
+ }
+ rg.read(pb, buf, n * sizeof(buf[0]));
+ if (!*pb) return;
+ uint32_t v = buf[n - 1];
+ if (rem == 0) {
+ v |= 1U << 31;
+ } else {
+ v &= (1U << rem) - 1;
+ v |= 1U << (rem - 1);
+ }
+ buf[n - 1] = v;
+ setArray(pb, z, buf, n);
+}
+
+inline void getRandPrime(bool *pb, mpz_class& z, size_t bitSize, fp::RandGen rg = fp::RandGen(), bool setSecondBit = false, bool mustBe3mod4 = false)
+{
+ if (rg.isZero()) rg = fp::RandGen::get();
+ assert(bitSize > 2);
+ for (;;) {
+ getRand(pb, z, bitSize, rg);
+ if (!*pb) return;
+ if (setSecondBit) {
+ z |= mpz_class(1) << (bitSize - 2);
+ }
+ if (mustBe3mod4) {
+ z |= 3;
+ }
+ bool ret = isPrime(pb, z);
+ if (!*pb) return;
+ if (ret) return;
+ }
+}
+inline mpz_class getQuadraticNonResidue(const mpz_class& p)
+{
+ mpz_class g = 2;
+ while (legendre(g, p) > 0) {
+ ++g;
+ }
+ return g;
+}
+
+namespace impl {
+
+template<class Vec>
+void convertToBinary(Vec& v, const mpz_class& x)
+{
+ const size_t len = gmp::getBitSize(x);
+ v.resize(len);
+ for (size_t i = 0; i < len; i++) {
+ v[i] = gmp::testBit(x, len - 1 - i) ? 1 : 0;
+ }
+}
+
+template<class Vec>
+size_t getContinuousVal(const Vec& v, size_t pos, int val)
+{
+ while (pos >= 2) {
+ if (v[pos] != val) break;
+ pos--;
+ }
+ return pos;
+}
+
+template<class Vec>
+void convertToNAF(Vec& v, const Vec& in)
+{
+ v.copy(in);
+ size_t pos = v.size() - 1;
+ for (;;) {
+ size_t p = getContinuousVal(v, pos, 0);
+ if (p == 1) return;
+ assert(v[p] == 1);
+ size_t q = getContinuousVal(v, p, 1);
+ if (q == 1) return;
+ assert(v[q] == 0);
+ if (p - q <= 1) {
+ pos = p - 1;
+ continue;
+ }
+ v[q] = 1;
+ for (size_t i = q + 1; i < p; i++) {
+ v[i] = 0;
+ }
+ v[p] = -1;
+ pos = q;
+ }
+}
+
+template<class Vec>
+size_t getNumOfNonZeroElement(const Vec& v)
+{
+ size_t w = 0;
+ for (size_t i = 0; i < v.size(); i++) {
+ if (v[i]) w++;
+ }
+ return w;
+}
+
+} // impl
+
+/*
+ compute a repl of x which has smaller Hamming weights.
+ return true if naf is selected
+*/
+template<class Vec>
+bool getNAF(Vec& v, const mpz_class& x)
+{
+ Vec bin;
+ impl::convertToBinary(bin, x);
+ Vec naf;
+ impl::convertToNAF(naf, bin);
+ const size_t binW = impl::getNumOfNonZeroElement(bin);
+ const size_t nafW = impl::getNumOfNonZeroElement(naf);
+ if (nafW < binW) {
+ v.swap(naf);
+ return true;
+ } else {
+ v.swap(bin);
+ return false;
+ }
+}
+
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+inline void setStr(mpz_class& z, const std::string& str, int base = 0)
+{
+ bool b;
+ setStr(&b, z, str.c_str(), base);
+ if (!b) throw cybozu::Exception("gmp:setStr");
+}
+template<class T>
+void setArray(mpz_class& z, const T *buf, size_t n)
+{
+ bool b;
+ setArray(&b, z, buf, n);
+ if (!b) throw cybozu::Exception("gmp:setArray");
+}
+template<class T>
+void getArray(T *buf, size_t maxSize, const mpz_class& x)
+{
+ bool b;
+ getArray(&b, buf, maxSize, x);
+ if (!b) throw cybozu::Exception("gmp:getArray");
+}
+inline bool isPrime(const mpz_class& x)
+{
+ bool b;
+ bool ret = isPrime(&b, x);
+ if (!b) throw cybozu::Exception("gmp:isPrime");
+ return ret;
+}
+inline void getRand(mpz_class& z, size_t bitSize, fp::RandGen rg = fp::RandGen())
+{
+ bool b;
+ getRand(&b, z, bitSize, rg);
+ if (!b) throw cybozu::Exception("gmp:getRand");
+}
+inline void getRandPrime(mpz_class& z, size_t bitSize, fp::RandGen rg = fp::RandGen(), bool setSecondBit = false, bool mustBe3mod4 = false)
+{
+ bool b;
+ getRandPrime(&b, z, bitSize, rg, setSecondBit, mustBe3mod4);
+ if (!b) throw cybozu::Exception("gmp:getRandPrime");
+}
+#endif
+
+
+} // mcl::gmp
+
+/*
+ Tonelli-Shanks
+*/
+class SquareRoot {
+ bool isPrecomputed_;
+ bool isPrime;
+ mpz_class p;
+ mpz_class g;
+ int r;
+ mpz_class q; // p - 1 = 2^r q
+ mpz_class s; // s = g^q
+ mpz_class q_add_1_div_2;
+ struct Tbl {
+ const char *p;
+ const char *g;
+ int r;
+ const char *q;
+ const char *s;
+ const char *q_add_1_div_2;
+ };
+ bool setIfPrecomputed(const mpz_class& p_)
+ {
+ static const Tbl tbl[] = {
+ { // BN254.p
+ "2523648240000001ba344d80000000086121000000000013a700000000000013",
+ "2",
+ 1,
+ "1291b24120000000dd1a26c0000000043090800000000009d380000000000009",
+ "2523648240000001ba344d80000000086121000000000013a700000000000012",
+ "948d920900000006e8d1360000000021848400000000004e9c0000000000005",
+ },
+ { // BN254.r
+ "2523648240000001ba344d8000000007ff9f800000000010a10000000000000d",
+ "2",
+ 2,
+ "948d920900000006e8d136000000001ffe7e000000000042840000000000003",
+ "9366c4800000000555150000000000122400000000000015",
+ "4a46c9048000000374689b000000000fff3f000000000021420000000000002",
+ },
+ { // BLS12_381,p
+ "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab",
+ "2",
+ 1,
+ "d0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555",
+ "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
+ "680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaab",
+ },
+ { // BLS12_381.r
+ "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001",
+ "5",
+ 32,
+ "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff",
+ "212d79e5b416b6f0fd56dc8d168d6c0c4024ff270b3e0941b788f500b912f1f",
+ "39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff80000000",
+ },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ mpz_class targetPrime;
+ bool b;
+ mcl::gmp::setStr(&b, targetPrime, tbl[i].p, 16);
+ if (!b) continue;
+ if (targetPrime != p_) continue;
+ isPrime = true;
+ p = p_;
+ mcl::gmp::setStr(&b, g, tbl[i].g, 16);
+ if (!b) continue;
+ r = tbl[i].r;
+ mcl::gmp::setStr(&b, q, tbl[i].q, 16);
+ if (!b) continue;
+ mcl::gmp::setStr(&b, s, tbl[i].s, 16);
+ if (!b) continue;
+ mcl::gmp::setStr(&b, q_add_1_div_2, tbl[i].q_add_1_div_2, 16);
+ if (!b) continue;
+ isPrecomputed_ = true;
+ return true;
+ }
+ return false;
+ }
+public:
+ SquareRoot() { clear(); }
+ bool isPrecomputed() const { return isPrecomputed_; }
+ void clear()
+ {
+ isPrecomputed_ = false;
+ isPrime = false;
+ p = 0;
+ g = 0;
+ r = 0;
+ q = 0;
+ s = 0;
+ q_add_1_div_2 = 0;
+ }
+#if !defined(CYBOZU_DONT_USE_USE_STRING) && !defined(CYBOZU_DONT_USE_EXCEPTION)
+ void dump() const
+ {
+ printf("\"%s\",\n", mcl::gmp::getStr(p, 16).c_str());
+ printf("\"%s\",\n", mcl::gmp::getStr(g, 16).c_str());
+ printf("%d,\n", r);
+ printf("\"%s\",\n", mcl::gmp::getStr(q, 16).c_str());
+ printf("\"%s\",\n", mcl::gmp::getStr(s, 16).c_str());
+ printf("\"%s\",\n", mcl::gmp::getStr(q_add_1_div_2, 16).c_str());
+ }
+#endif
+ void set(bool *pb, const mpz_class& _p, bool usePrecomputedTable = true)
+ {
+ if (usePrecomputedTable && setIfPrecomputed(_p)) {
+ *pb = true;
+ return;
+ }
+ p = _p;
+ if (p <= 2) {
+ *pb = false;
+ return;
+ }
+ isPrime = gmp::isPrime(pb, p);
+ if (!*pb) return;
+ if (!isPrime) {
+ *pb = false;
+ return;
+ }
+ g = gmp::getQuadraticNonResidue(p);
+ // p - 1 = 2^r q, q is odd
+ r = 0;
+ q = p - 1;
+ while ((q & 1) == 0) {
+ r++;
+ q /= 2;
+ }
+ gmp::powMod(s, g, q, p);
+ q_add_1_div_2 = (q + 1) / 2;
+ *pb = true;
+ }
+ /*
+ solve x^2 = a mod p
+ */
+ bool get(mpz_class& x, const mpz_class& a) const
+ {
+ if (!isPrime) {
+ return false;
+ }
+ if (a == 0) {
+ x = 0;
+ return true;
+ }
+ if (gmp::legendre(a, p) < 0) return false;
+ if (r == 1) {
+ // (p + 1) / 4 = (q + 1) / 2
+ gmp::powMod(x, a, q_add_1_div_2, p);
+ return true;
+ }
+ mpz_class c = s, d;
+ int e = r;
+ gmp::powMod(d, a, q, p);
+ gmp::powMod(x, a, q_add_1_div_2, p); // destroy a if &x == &a
+ mpz_class dd;
+ mpz_class b;
+ while (d != 1) {
+ int i = 1;
+ dd = d * d; dd %= p;
+ while (dd != 1) {
+ dd *= dd; dd %= p;
+ i++;
+ }
+ b = 1;
+ b <<= e - i - 1;
+ gmp::powMod(b, c, b, p);
+ x *= b; x %= p;
+ c = b * b; c %= p;
+ d *= c; d %= p;
+ e = i;
+ }
+ return true;
+ }
+ /*
+ solve x^2 = a in Fp
+ */
+ template<class Fp>
+ bool get(Fp& x, const Fp& a) const
+ {
+ assert(Fp::getOp().mp == p);
+ if (a == 0) {
+ x = 0;
+ return true;
+ }
+ {
+ bool b;
+ mpz_class aa;
+ a.getMpz(&b, aa);
+ assert(b);
+ if (gmp::legendre(aa, p) < 0) return false;
+ }
+ if (r == 1) {
+ // (p + 1) / 4 = (q + 1) / 2
+ Fp::pow(x, a, q_add_1_div_2);
+ return true;
+ }
+ Fp c, d;
+ {
+ bool b;
+ c.setMpz(&b, s);
+ assert(b);
+ }
+ int e = r;
+ Fp::pow(d, a, q);
+ Fp::pow(x, a, q_add_1_div_2); // destroy a if &x == &a
+ Fp dd;
+ Fp b;
+ while (!d.isOne()) {
+ int i = 1;
+ Fp::sqr(dd, d);
+ while (!dd.isOne()) {
+ dd *= dd;
+ i++;
+ }
+ b = 1;
+// b <<= e - i - 1;
+ for (int j = 0; j < e - i - 1; j++) {
+ b += b;
+ }
+ Fp::pow(b, c, b);
+ x *= b;
+ Fp::sqr(c, b);
+ d *= c;
+ e = i;
+ }
+ return true;
+ }
+ bool operator==(const SquareRoot& rhs) const
+ {
+ return isPrime == rhs.isPrime && p == rhs.p && g == rhs.g && r == rhs.r
+ && q == rhs.q && s == rhs.s && q_add_1_div_2 == rhs.q_add_1_div_2;
+ }
+ bool operator!=(const SquareRoot& rhs) const { return !operator==(rhs); }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ void set(const mpz_class& _p)
+ {
+ bool b;
+ set(&b, _p);
+ if (!b) throw cybozu::Exception("gmp:SquareRoot:set");
+ }
+#endif
+};
+
+/*
+ Barrett Reduction
+ for non GMP version
+ mod of GMP is faster than Modp
+*/
+struct Modp {
+ static const size_t unitBitSize = sizeof(mcl::fp::Unit) * 8;
+ mpz_class p_;
+ mpz_class u_;
+ mpz_class a_;
+ size_t pBitSize_;
+ size_t N_;
+ bool initU_; // Is u_ initialized?
+ Modp()
+ : pBitSize_(0)
+ , N_(0)
+ , initU_(false)
+ {
+ }
+ // x &= 1 << (unitBitSize * unitSize)
+ void shrinkSize(mpz_class &x, size_t unitSize) const
+ {
+ size_t u = gmp::getUnitSize(x);
+ if (u < unitSize) return;
+ bool b;
+ gmp::setArray(&b, x, gmp::getUnit(x), unitSize);
+ (void)b;
+ assert(b);
+ }
+ // p_ is set by p and compute (u_, a_) if possible
+ void init(const mpz_class& p)
+ {
+ p_ = p;
+ pBitSize_ = gmp::getBitSize(p);
+ N_ = (pBitSize_ + unitBitSize - 1) / unitBitSize;
+ initU_ = false;
+#if 0
+ u_ = (mpz_class(1) << (unitBitSize * 2 * N_)) / p_;
+#else
+ /*
+ 1 << (unitBitSize * 2 * N_) may be overflow,
+ so use (1 << (unitBitSize * 2 * N_)) - 1 because u_ is same.
+ */
+ uint8_t buf[48 * 2];
+ const size_t byteSize = unitBitSize / 8 * 2 * N_;
+ if (byteSize > sizeof(buf)) return;
+ memset(buf, 0xff, byteSize);
+ bool b;
+ gmp::setArray(&b, u_, buf, byteSize);
+ if (!b) return;
+#endif
+ u_ /= p_;
+ a_ = mpz_class(1) << (unitBitSize * (N_ + 1));
+ initU_ = true;
+ }
+ void modp(mpz_class& r, const mpz_class& t) const
+ {
+ assert(p_ > 0);
+ const size_t tBitSize = gmp::getBitSize(t);
+ // use gmp::mod if init() fails or t is too large
+ if (tBitSize > unitBitSize * 2 * N_ || !initU_) {
+ gmp::mod(r, t, p_);
+ return;
+ }
+ if (tBitSize < pBitSize_) {
+ r = t;
+ return;
+ }
+ // mod is faster than modp if t is small
+ if (tBitSize <= unitBitSize * N_) {
+ gmp::mod(r, t, p_);
+ return;
+ }
+ mpz_class q;
+ q = t;
+ q >>= unitBitSize * (N_ - 1);
+ q *= u_;
+ q >>= unitBitSize * (N_ + 1);
+ q *= p_;
+ shrinkSize(q, N_ + 1);
+ r = t;
+ shrinkSize(r, N_ + 1);
+ r -= q;
+ if (r < 0) {
+ r += a_;
+ }
+ if (r >= p_) {
+ r -= p_;
+ }
+ }
+};
+
+} // mcl
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/impl/bn_c_impl.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/impl/bn_c_impl.hpp
new file mode 100644
index 000000000..bec2466dd
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/impl/bn_c_impl.hpp
@@ -0,0 +1,643 @@
+/*
+ This is an internal header
+ Do not include this
+*/
+#define MCLBN_DLL_EXPORT
+#include <mcl/bn.h>
+
+#if MCLBN_FP_UNIT_SIZE == 4 && MCLBN_FR_UNIT_SIZE == 4
+#include <mcl/bn256.hpp>
+#elif MCLBN_FP_UNIT_SIZE == 6 && MCLBN_FR_UNIT_SIZE == 6
+#include <mcl/bn384.hpp>
+#elif MCLBN_FP_UNIT_SIZE == 6 && MCLBN_FR_UNIT_SIZE == 4
+#include <mcl/bls12_381.hpp>
+#elif MCLBN_FP_UNIT_SIZE == 8 && MCLBN_FR_UNIT_SIZE == 8
+#include <mcl/bn512.hpp>
+#else
+ #error "not supported size"
+#endif
+#include <mcl/lagrange.hpp>
+#include <mcl/ecparam.hpp>
+using namespace mcl::bn;
+
+static Fr *cast(mclBnFr *p) { return reinterpret_cast<Fr*>(p); }
+static const Fr *cast(const mclBnFr *p) { return reinterpret_cast<const Fr*>(p); }
+
+static G1 *cast(mclBnG1 *p) { return reinterpret_cast<G1*>(p); }
+static const G1 *cast(const mclBnG1 *p) { return reinterpret_cast<const G1*>(p); }
+
+static G2 *cast(mclBnG2 *p) { return reinterpret_cast<G2*>(p); }
+static const G2 *cast(const mclBnG2 *p) { return reinterpret_cast<const G2*>(p); }
+
+static Fp12 *cast(mclBnGT *p) { return reinterpret_cast<Fp12*>(p); }
+static const Fp12 *cast(const mclBnGT *p) { return reinterpret_cast<const Fp12*>(p); }
+
+static Fp6 *cast(uint64_t *p) { return reinterpret_cast<Fp6*>(p); }
+static const Fp6 *cast(const uint64_t *p) { return reinterpret_cast<const Fp6*>(p); }
+
+static Fp2 *cast(mclBnFp2 *p) { return reinterpret_cast<Fp2*>(p); }
+static const Fp2 *cast(const mclBnFp2 *p) { return reinterpret_cast<const Fp2*>(p); }
+
+static Fp *cast(mclBnFp *p) { return reinterpret_cast<Fp*>(p); }
+static const Fp *cast(const mclBnFp *p) { return reinterpret_cast<const Fp*>(p); }
+
+template<class T>
+int setStr(T *x, const char *buf, mclSize bufSize, int ioMode)
+{
+ size_t n = cast(x)->deserialize(buf, bufSize, ioMode);
+ return n > 0 ? 0 : -1;
+}
+
+#ifdef __EMSCRIPTEN__
+// use these functions forcibly
+extern "C" MCLBN_DLL_API void *mclBnMalloc(size_t n)
+{
+ return malloc(n);
+}
+extern "C" MCLBN_DLL_API void mclBnFree(void *p)
+{
+ free(p);
+}
+#endif
+
+int mclBn_getVersion()
+{
+ return mcl::version;
+}
+
+int mclBn_init(int curve, int compiledTimeVar)
+{
+ if (compiledTimeVar != MCLBN_COMPILED_TIME_VAR) {
+ return -(compiledTimeVar | (MCLBN_COMPILED_TIME_VAR * 100));
+ }
+ if (MCL_EC_BEGIN <= curve && curve < MCL_EC_END) {
+ const mcl::EcParam *para = mcl::getEcParam(curve);
+ if (para == 0) return -2;
+ bool b;
+ initG1only(&b, *para);
+ return b ? 0 : -1;
+ }
+ const mcl::CurveParam& cp = mcl::getCurveParam(curve);
+ bool b;
+ initPairing(&b, cp);
+ return b ? 0 : -1;
+}
+
+int mclBn_getOpUnitSize()
+{
+ return (int)Fp::getUnitSize() * sizeof(mcl::fp::Unit) / sizeof(uint64_t);
+}
+
+int mclBn_getG1ByteSize()
+{
+ return mclBn_getFpByteSize();
+}
+
+int mclBn_getFrByteSize()
+{
+ return (int)Fr::getByteSize();
+}
+
+int mclBn_getFpByteSize()
+{
+ return (int)Fp::getByteSize();
+}
+
+mclSize mclBn_getCurveOrder(char *buf, mclSize maxBufSize)
+{
+ return Fr::getModulo(buf, maxBufSize);
+}
+
+mclSize mclBn_getFieldOrder(char *buf, mclSize maxBufSize)
+{
+ return Fp::getModulo(buf, maxBufSize);
+}
+
+////////////////////////////////////////////////
+// set zero
+void mclBnFr_clear(mclBnFr *x)
+{
+ cast(x)->clear();
+}
+
+// set x to y
+void mclBnFr_setInt(mclBnFr *y, mclInt x)
+{
+ *cast(y) = x;
+}
+void mclBnFr_setInt32(mclBnFr *y, int x)
+{
+ *cast(y) = x;
+}
+
+int mclBnFr_setStr(mclBnFr *x, const char *buf, mclSize bufSize, int ioMode)
+{
+ return setStr(x, buf, bufSize, ioMode);
+}
+int mclBnFr_setLittleEndian(mclBnFr *x, const void *buf, mclSize bufSize)
+{
+ cast(x)->setArrayMask((const char *)buf, bufSize);
+ return 0;
+}
+int mclBnFr_setLittleEndianMod(mclBnFr *x, const void *buf, mclSize bufSize)
+{
+ bool b;
+ cast(x)->setArray(&b, (const char *)buf, bufSize, mcl::fp::Mod);
+ return b ? 0 : -1;
+}
+mclSize mclBnFr_deserialize(mclBnFr *x, const void *buf, mclSize bufSize)
+{
+ return (mclSize)cast(x)->deserialize(buf, bufSize);
+}
+// return 1 if true
+int mclBnFr_isValid(const mclBnFr *x)
+{
+ return cast(x)->isValid();
+}
+int mclBnFr_isEqual(const mclBnFr *x, const mclBnFr *y)
+{
+ return *cast(x) == *cast(y);
+}
+int mclBnFr_isZero(const mclBnFr *x)
+{
+ return cast(x)->isZero();
+}
+int mclBnFr_isOne(const mclBnFr *x)
+{
+ return cast(x)->isOne();
+}
+
+#ifndef MCL_DONT_USE_CSRPNG
+int mclBnFr_setByCSPRNG(mclBnFr *x)
+{
+ bool b;
+ cast(x)->setByCSPRNG(&b);
+ return b ? 0 : -1;
+}
+void mclBn_setRandFunc(void *self, unsigned int (*readFunc)(void *self, void *buf, unsigned int bufSize))
+{
+ mcl::fp::RandGen::setRandFunc(self, readFunc);
+}
+#endif
+
+// hash(buf) and set x
+int mclBnFr_setHashOf(mclBnFr *x, const void *buf, mclSize bufSize)
+{
+ cast(x)->setHashOf(buf, bufSize);
+ return 0;
+}
+
+mclSize mclBnFr_getStr(char *buf, mclSize maxBufSize, const mclBnFr *x, int ioMode)
+{
+ return cast(x)->getStr(buf, maxBufSize, ioMode);
+}
+mclSize mclBnFr_serialize(void *buf, mclSize maxBufSize, const mclBnFr *x)
+{
+ return (mclSize)cast(x)->serialize(buf, maxBufSize);
+}
+
+void mclBnFr_neg(mclBnFr *y, const mclBnFr *x)
+{
+ Fr::neg(*cast(y), *cast(x));
+}
+void mclBnFr_inv(mclBnFr *y, const mclBnFr *x)
+{
+ Fr::inv(*cast(y), *cast(x));
+}
+void mclBnFr_sqr(mclBnFr *y, const mclBnFr *x)
+{
+ Fr::sqr(*cast(y), *cast(x));
+}
+void mclBnFr_add(mclBnFr *z, const mclBnFr *x, const mclBnFr *y)
+{
+ Fr::add(*cast(z),*cast(x), *cast(y));
+}
+void mclBnFr_sub(mclBnFr *z, const mclBnFr *x, const mclBnFr *y)
+{
+ Fr::sub(*cast(z),*cast(x), *cast(y));
+}
+void mclBnFr_mul(mclBnFr *z, const mclBnFr *x, const mclBnFr *y)
+{
+ Fr::mul(*cast(z),*cast(x), *cast(y));
+}
+void mclBnFr_div(mclBnFr *z, const mclBnFr *x, const mclBnFr *y)
+{
+ Fr::div(*cast(z),*cast(x), *cast(y));
+}
+
+////////////////////////////////////////////////
+// set zero
+void mclBnG1_clear(mclBnG1 *x)
+{
+ cast(x)->clear();
+}
+
+int mclBnG1_setStr(mclBnG1 *x, const char *buf, mclSize bufSize, int ioMode)
+{
+ return setStr(x, buf, bufSize, ioMode);
+}
+mclSize mclBnG1_deserialize(mclBnG1 *x, const void *buf, mclSize bufSize)
+{
+ return (mclSize)cast(x)->deserialize(buf, bufSize);
+}
+
+// return 1 if true
+int mclBnG1_isValid(const mclBnG1 *x)
+{
+ return cast(x)->isValid();
+}
+int mclBnG1_isEqual(const mclBnG1 *x, const mclBnG1 *y)
+{
+ return *cast(x) == *cast(y);
+}
+int mclBnG1_isZero(const mclBnG1 *x)
+{
+ return cast(x)->isZero();
+}
+int mclBnG1_isValidOrder(const mclBnG1 *x)
+{
+ return cast(x)->isValidOrder();
+}
+
+int mclBnG1_hashAndMapTo(mclBnG1 *x, const void *buf, mclSize bufSize)
+{
+ hashAndMapToG1(*cast(x), buf, bufSize);
+ return 0;
+}
+
+mclSize mclBnG1_getStr(char *buf, mclSize maxBufSize, const mclBnG1 *x, int ioMode)
+{
+ return cast(x)->getStr(buf, maxBufSize, ioMode);
+}
+
+mclSize mclBnG1_serialize(void *buf, mclSize maxBufSize, const mclBnG1 *x)
+{
+ return (mclSize)cast(x)->serialize(buf, maxBufSize);
+}
+
+void mclBnG1_neg(mclBnG1 *y, const mclBnG1 *x)
+{
+ G1::neg(*cast(y), *cast(x));
+}
+void mclBnG1_dbl(mclBnG1 *y, const mclBnG1 *x)
+{
+ G1::dbl(*cast(y), *cast(x));
+}
+void mclBnG1_normalize(mclBnG1 *y, const mclBnG1 *x)
+{
+ G1::normalize(*cast(y), *cast(x));
+}
+void mclBnG1_add(mclBnG1 *z, const mclBnG1 *x, const mclBnG1 *y)
+{
+ G1::add(*cast(z),*cast(x), *cast(y));
+}
+void mclBnG1_sub(mclBnG1 *z, const mclBnG1 *x, const mclBnG1 *y)
+{
+ G1::sub(*cast(z),*cast(x), *cast(y));
+}
+void mclBnG1_mul(mclBnG1 *z, const mclBnG1 *x, const mclBnFr *y)
+{
+ G1::mul(*cast(z),*cast(x), *cast(y));
+}
+void mclBnG1_mulCT(mclBnG1 *z, const mclBnG1 *x, const mclBnFr *y)
+{
+ G1::mulCT(*cast(z),*cast(x), *cast(y));
+}
+
+////////////////////////////////////////////////
+// set zero
+void mclBnG2_clear(mclBnG2 *x)
+{
+ cast(x)->clear();
+}
+
+int mclBnG2_setStr(mclBnG2 *x, const char *buf, mclSize bufSize, int ioMode)
+{
+ return setStr(x, buf, bufSize, ioMode);
+}
+mclSize mclBnG2_deserialize(mclBnG2 *x, const void *buf, mclSize bufSize)
+{
+ return (mclSize)cast(x)->deserialize(buf, bufSize);
+}
+
+// return 1 if true
+int mclBnG2_isValid(const mclBnG2 *x)
+{
+ return cast(x)->isValid();
+}
+int mclBnG2_isEqual(const mclBnG2 *x, const mclBnG2 *y)
+{
+ return *cast(x) == *cast(y);
+}
+int mclBnG2_isZero(const mclBnG2 *x)
+{
+ return cast(x)->isZero();
+}
+int mclBnG2_isValidOrder(const mclBnG2 *x)
+{
+ return cast(x)->isValidOrder();
+}
+
+int mclBnG2_hashAndMapTo(mclBnG2 *x, const void *buf, mclSize bufSize)
+{
+ hashAndMapToG2(*cast(x), buf, bufSize);
+ return 0;
+}
+
+mclSize mclBnG2_getStr(char *buf, mclSize maxBufSize, const mclBnG2 *x, int ioMode)
+{
+ return cast(x)->getStr(buf, maxBufSize, ioMode);
+}
+
+mclSize mclBnG2_serialize(void *buf, mclSize maxBufSize, const mclBnG2 *x)
+{
+ return (mclSize)cast(x)->serialize(buf, maxBufSize);
+}
+
+void mclBnG2_neg(mclBnG2 *y, const mclBnG2 *x)
+{
+ G2::neg(*cast(y), *cast(x));
+}
+void mclBnG2_dbl(mclBnG2 *y, const mclBnG2 *x)
+{
+ G2::dbl(*cast(y), *cast(x));
+}
+void mclBnG2_normalize(mclBnG2 *y, const mclBnG2 *x)
+{
+ G2::normalize(*cast(y), *cast(x));
+}
+void mclBnG2_add(mclBnG2 *z, const mclBnG2 *x, const mclBnG2 *y)
+{
+ G2::add(*cast(z),*cast(x), *cast(y));
+}
+void mclBnG2_sub(mclBnG2 *z, const mclBnG2 *x, const mclBnG2 *y)
+{
+ G2::sub(*cast(z),*cast(x), *cast(y));
+}
+void mclBnG2_mul(mclBnG2 *z, const mclBnG2 *x, const mclBnFr *y)
+{
+ G2::mul(*cast(z),*cast(x), *cast(y));
+}
+void mclBnG2_mulCT(mclBnG2 *z, const mclBnG2 *x, const mclBnFr *y)
+{
+ G2::mulCT(*cast(z),*cast(x), *cast(y));
+}
+
+////////////////////////////////////////////////
+// set zero
+void mclBnGT_clear(mclBnGT *x)
+{
+ cast(x)->clear();
+}
+void mclBnGT_setInt(mclBnGT *y, mclInt x)
+{
+ cast(y)->clear();
+ *(cast(y)->getFp0()) = x;
+}
+void mclBnGT_setInt32(mclBnGT *y, int x)
+{
+ cast(y)->clear();
+ *(cast(y)->getFp0()) = x;
+}
+
+int mclBnGT_setStr(mclBnGT *x, const char *buf, mclSize bufSize, int ioMode)
+{
+ return setStr(x, buf, bufSize, ioMode);
+}
+mclSize mclBnGT_deserialize(mclBnGT *x, const void *buf, mclSize bufSize)
+{
+ return (mclSize)cast(x)->deserialize(buf, bufSize);
+}
+
+// return 1 if true
+int mclBnGT_isEqual(const mclBnGT *x, const mclBnGT *y)
+{
+ return *cast(x) == *cast(y);
+}
+int mclBnGT_isZero(const mclBnGT *x)
+{
+ return cast(x)->isZero();
+}
+int mclBnGT_isOne(const mclBnGT *x)
+{
+ return cast(x)->isOne();
+}
+
+mclSize mclBnGT_getStr(char *buf, mclSize maxBufSize, const mclBnGT *x, int ioMode)
+{
+ return cast(x)->getStr(buf, maxBufSize, ioMode);
+}
+
+mclSize mclBnGT_serialize(void *buf, mclSize maxBufSize, const mclBnGT *x)
+{
+ return (mclSize)cast(x)->serialize(buf, maxBufSize);
+}
+
+void mclBnGT_neg(mclBnGT *y, const mclBnGT *x)
+{
+ Fp12::neg(*cast(y), *cast(x));
+}
+void mclBnGT_inv(mclBnGT *y, const mclBnGT *x)
+{
+ Fp12::inv(*cast(y), *cast(x));
+}
+void mclBnGT_sqr(mclBnGT *y, const mclBnGT *x)
+{
+ Fp12::sqr(*cast(y), *cast(x));
+}
+void mclBnGT_add(mclBnGT *z, const mclBnGT *x, const mclBnGT *y)
+{
+ Fp12::add(*cast(z),*cast(x), *cast(y));
+}
+void mclBnGT_sub(mclBnGT *z, const mclBnGT *x, const mclBnGT *y)
+{
+ Fp12::sub(*cast(z),*cast(x), *cast(y));
+}
+void mclBnGT_mul(mclBnGT *z, const mclBnGT *x, const mclBnGT *y)
+{
+ Fp12::mul(*cast(z),*cast(x), *cast(y));
+}
+void mclBnGT_div(mclBnGT *z, const mclBnGT *x, const mclBnGT *y)
+{
+ Fp12::div(*cast(z),*cast(x), *cast(y));
+}
+
+void mclBnGT_pow(mclBnGT *z, const mclBnGT *x, const mclBnFr *y)
+{
+ Fp12::pow(*cast(z), *cast(x), *cast(y));
+}
+void mclBnGT_powGeneric(mclBnGT *z, const mclBnGT *x, const mclBnFr *y)
+{
+ Fp12::powGeneric(*cast(z), *cast(x), *cast(y));
+}
+
+void mclBn_pairing(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y)
+{
+ pairing(*cast(z), *cast(x), *cast(y));
+}
+void mclBn_finalExp(mclBnGT *y, const mclBnGT *x)
+{
+ finalExp(*cast(y), *cast(x));
+}
+void mclBn_millerLoop(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y)
+{
+ millerLoop(*cast(z), *cast(x), *cast(y));
+}
+int mclBn_getUint64NumToPrecompute(void)
+{
+ return int(BN::param.precomputedQcoeffSize * sizeof(Fp6) / sizeof(uint64_t));
+}
+
+void mclBn_precomputeG2(uint64_t *Qbuf, const mclBnG2 *Q)
+{
+ precomputeG2(cast(Qbuf), *cast(Q));
+}
+
+void mclBn_precomputedMillerLoop(mclBnGT *f, const mclBnG1 *P, const uint64_t *Qbuf)
+{
+ precomputedMillerLoop(*cast(f), *cast(P), cast(Qbuf));
+}
+
+void mclBn_precomputedMillerLoop2(mclBnGT *f, const mclBnG1 *P1, const uint64_t *Q1buf, const mclBnG1 *P2, const uint64_t *Q2buf)
+{
+ precomputedMillerLoop2(*cast(f), *cast(P1), cast(Q1buf), *cast(P2), cast(Q2buf));
+}
+
+void mclBn_precomputedMillerLoop2mixed(mclBnGT *f, const mclBnG1 *P1, const mclBnG2 *Q1, const mclBnG1 *P2, const uint64_t *Q2buf)
+{
+ precomputedMillerLoop2mixed(*cast(f), *cast(P1), *cast(Q1), *cast(P2), cast(Q2buf));
+}
+
+int mclBn_FrLagrangeInterpolation(mclBnFr *out, const mclBnFr *xVec, const mclBnFr *yVec, mclSize k)
+{
+ bool b;
+ mcl::LagrangeInterpolation(&b, *cast(out), cast(xVec), cast(yVec), k);
+ return b ? 0 : -1;
+}
+int mclBn_G1LagrangeInterpolation(mclBnG1 *out, const mclBnFr *xVec, const mclBnG1 *yVec, mclSize k)
+{
+ bool b;
+ mcl::LagrangeInterpolation(&b, *cast(out), cast(xVec), cast(yVec), k);
+ return b ? 0 : -1;
+}
+int mclBn_G2LagrangeInterpolation(mclBnG2 *out, const mclBnFr *xVec, const mclBnG2 *yVec, mclSize k)
+{
+ bool b;
+ mcl::LagrangeInterpolation(&b, *cast(out), cast(xVec), cast(yVec), k);
+ return b ? 0 : -1;
+}
+int mclBn_FrEvaluatePolynomial(mclBnFr *out, const mclBnFr *cVec, mclSize cSize, const mclBnFr *x)
+{
+ bool b;
+ mcl::evaluatePolynomial(&b, *cast(out), cast(cVec), cSize, *cast(x));
+ return b ? 0 : -1;
+}
+int mclBn_G1EvaluatePolynomial(mclBnG1 *out, const mclBnG1 *cVec, mclSize cSize, const mclBnFr *x)
+{
+ bool b;
+ mcl::evaluatePolynomial(&b, *cast(out), cast(cVec), cSize, *cast(x));
+ return b ? 0 : -1;
+}
+int mclBn_G2EvaluatePolynomial(mclBnG2 *out, const mclBnG2 *cVec, mclSize cSize, const mclBnFr *x)
+{
+ bool b;
+ mcl::evaluatePolynomial(&b, *cast(out), cast(cVec), cSize, *cast(x));
+ return b ? 0 : -1;
+}
+
+void mclBn_verifyOrderG1(int doVerify)
+{
+ verifyOrderG1(doVerify != 0);
+}
+
+void mclBn_verifyOrderG2(int doVerify)
+{
+ verifyOrderG2(doVerify != 0);
+}
+
+mclSize mclBnFp_getStr(char *buf, mclSize maxBufSize, const mclBnFp *x, int ioMode)
+{
+ return cast(x)->getStr(buf, maxBufSize, ioMode);
+}
+int mclBnFp_setStr(mclBnFp *x, const char *buf, mclSize bufSize, int ioMode)
+{
+ return setStr(x, buf, bufSize, ioMode);
+}
+mclSize mclBnFp_deserialize(mclBnFp *x, const void *buf, mclSize bufSize)
+{
+ return (mclSize)cast(x)->deserialize(buf, bufSize);
+}
+
+mclSize mclBnFp_serialize(void *buf, mclSize maxBufSize, const mclBnFp *x)
+{
+ return (mclSize)cast(x)->serialize(buf, maxBufSize);
+}
+
+void mclBnFp_clear(mclBnFp *x)
+{
+ cast(x)->clear();
+}
+
+int mclBnFp_setLittleEndian(mclBnFp *x, const void *buf, mclSize bufSize)
+{
+ cast(x)->setArrayMask((const char *)buf, bufSize);
+ return 0;
+}
+
+int mclBnFp_setLittleEndianMod(mclBnFp *x, const void *buf, mclSize bufSize)
+{
+ bool b;
+ cast(x)->setArray(&b, (const char *)buf, bufSize, mcl::fp::Mod);
+ return b ? 0 : -1;
+}
+int mclBnFp_isEqual(const mclBnFp *x, const mclBnFp *y)
+{
+ return *cast(x) == *cast(y);
+}
+
+int mclBnFp_setHashOf(mclBnFp *x, const void *buf, mclSize bufSize)
+{
+ cast(x)->setHashOf(buf, bufSize);
+ return 0;
+}
+
+int mclBnFp_mapToG1(mclBnG1 *y, const mclBnFp *x)
+{
+ bool b;
+ mapToG1(&b, *cast(y), *cast(x));
+ return b ? 0 : -1;
+}
+
+mclSize mclBnFp2_deserialize(mclBnFp2 *x, const void *buf, mclSize bufSize)
+{
+ return (mclSize)cast(x)->deserialize(buf, bufSize);
+}
+
+mclSize mclBnFp2_serialize(void *buf, mclSize maxBufSize, const mclBnFp2 *x)
+{
+ return (mclSize)cast(x)->serialize(buf, maxBufSize);
+}
+
+void mclBnFp2_clear(mclBnFp2 *x)
+{
+ cast(x)->clear();
+}
+
+int mclBnFp2_isEqual(const mclBnFp2 *x, const mclBnFp2 *y)
+{
+ return *cast(x) == *cast(y);
+}
+
+int mclBnFp2_mapToG2(mclBnG2 *y, const mclBnFp2 *x)
+{
+ bool b;
+ mapToG2(&b, *cast(y), *cast(x));
+ return b ? 0 : -1;
+}
+
+int mclBnG1_getBasePoint(mclBnG1 *x)
+{
+ *cast(x) = mcl::bn::getG1basePoint();
+ return 0;
+}
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/lagrange.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/lagrange.hpp
new file mode 100644
index 000000000..18e0597ec
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/lagrange.hpp
@@ -0,0 +1,107 @@
+#pragma once
+/**
+ @file
+ @brief Lagrange Interpolation
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+namespace mcl {
+
+/*
+ recover out = f(0) by { (x, y) | x = S[i], y = f(x) = vec[i] }
+ @retval 0 if succeed else -1
+*/
+template<class G, class F>
+void LagrangeInterpolation(bool *pb, G& out, const F *S, const G *vec, size_t k)
+{
+ if (k == 0) {
+ *pb = false;
+ return;
+ }
+ if (k == 1) {
+ out = vec[0];
+ *pb = true;
+ return;
+ }
+ /*
+ delta_{i,S}(0) = prod_{j != i} S[j] / (S[j] - S[i]) = a / b
+ where a = prod S[j], b = S[i] * prod_{j != i} (S[j] - S[i])
+ */
+ F a = S[0];
+ for (size_t i = 1; i < k; i++) {
+ a *= S[i];
+ }
+ if (a.isZero()) {
+ *pb = false;
+ return;
+ }
+ /*
+ f(0) = sum_i f(S[i]) delta_{i,S}(0)
+ */
+ G r;
+ r.clear();
+ for (size_t i = 0; i < k; i++) {
+ F b = S[i];
+ for (size_t j = 0; j < k; j++) {
+ if (j != i) {
+ F v = S[j] - S[i];
+ if (v.isZero()) {
+ *pb = false;
+ return;
+ }
+ b *= v;
+ }
+ }
+ G t;
+ G::mul(t, vec[i], a / b);
+ r += t;
+ }
+ out = r;
+ *pb = true;
+}
+
+/*
+ out = f(x) = c[0] + c[1] * x + c[2] * x^2 + ... + c[cSize - 1] * x^(cSize - 1)
+ @retval 0 if succeed else -1 (if cSize == 0)
+*/
+template<class G, class T>
+void evaluatePolynomial(bool *pb, G& out, const G *c, size_t cSize, const T& x)
+{
+ if (cSize == 0) {
+ *pb = false;
+ return;
+ }
+ if (cSize == 1) {
+ out = c[0];
+ *pb = true;
+ return;
+ }
+ G y = c[cSize - 1];
+ for (int i = (int)cSize - 2; i >= 0; i--) {
+ G::mul(y, y, x);
+ G::add(y, y, c[i]);
+ }
+ out = y;
+ *pb = true;
+}
+
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+template<class G, class F>
+void LagrangeInterpolation(G& out, const F *S, const G *vec, size_t k)
+{
+ bool b;
+ LagrangeInterpolation(&b, out, S, vec, k);
+ if (!b) throw cybozu::Exception("LagrangeInterpolation");
+}
+
+template<class G, class T>
+void evaluatePolynomial(G& out, const G *c, size_t cSize, const T& x)
+{
+ bool b;
+ evaluatePolynomial(&b, out, c, cSize, x);
+ if (!b) throw cybozu::Exception("evaluatePolynomial");
+}
+#endif
+
+} // mcl
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/op.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/op.hpp
new file mode 100644
index 000000000..36d37035e
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/op.hpp
@@ -0,0 +1,389 @@
+#pragma once
+/**
+ @file
+ @brief definition of Op
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/gmp_util.hpp>
+#include <memory.h>
+#include <mcl/array.hpp>
+
+#ifndef MCL_MAX_BIT_SIZE
+ #define MCL_MAX_BIT_SIZE 521
+#endif
+#if defined(__EMSCRIPTEN__) || defined(__wasm__)
+ #define MCL_DONT_USE_XBYAK
+ #define MCL_DONT_USE_OPENSSL
+#endif
+#if !defined(MCL_DONT_USE_XBYAK) && (defined(_WIN64) || defined(__x86_64__)) && (MCL_SIZEOF_UNIT == 8)
+ #define MCL_USE_XBYAK
+ #define MCL_XBYAK_DIRECT_CALL
+#endif
+
+#define MCL_MAX_HASH_BIT_SIZE 512
+
+namespace mcl {
+
+static const int version = 0x092; /* 0xABC = A.BC */
+
+/*
+ specifies available string format mode for X::setIoMode()
+ // for Fp, Fp2, Fp6, Fp12
+ default(0) : IoDec
+ printable string(zero terminated, variable size)
+ IoBin(2) | IoDec(10) | IoHex(16) | IoBinPrefix | IoHexPrefix
+
+ byte string(not zero terminated, fixed size)
+ IoArray | IoArrayRaw
+ IoArray = IoSerialize
+
+ // for Ec
+ affine(0) | IoEcCompY | IoComp
+ default : affine
+
+ affine and IoEcCompY are available with ioMode for Fp
+ IoSerialize ignores ioMode for Fp
+
+ IoAuto
+ dec or hex according to ios_base::fmtflags
+ IoBin
+ binary number([01]+)
+ IoDec
+ decimal number
+ IoHex
+ hexadecimal number([0-9a-fA-F]+)
+ IoBinPrefix
+ 0b + <binary number>
+ IoHexPrefix
+ 0x + <hexadecimal number>
+ IoArray
+ array of Unit(fixed size = Fp::getByteSize())
+ IoArrayRaw
+ array of Unit(fixed size = Fp::getByteSize()) without Montgomery conversion
+
+ // for Ec::setIoMode()
+ IoEcAffine(default)
+ "0" ; infinity
+ "1 <x> <y>" ; affine coordinate
+
+ IoEcProj
+ "4" <x> <y> <z> ; projective or jacobi coordinate
+
+ IoEcCompY
+ 1-bit y prepresentation of elliptic curve
+ "2 <x>" ; compressed for even y
+ "3 <x>" ; compressed for odd y
+
+ IoSerialize
+ if isMSBserialize(): // p is not full bit
+ size = Fp::getByteSize()
+ use MSB of array of x for 1-bit y for prime p where (p % 8 != 0)
+ [0] ; infinity
+ <x> ; for even y
+ <x>|1 ; for odd y ; |1 means set MSB of x
+ else:
+ size = Fp::getByteSize() + 1
+ [0] ; infinity
+ 2 <x> ; for even y
+ 3 <x> ; for odd y
+*/
+enum IoMode {
+ IoAuto = 0, // dec or hex according to ios_base::fmtflags
+ IoBin = 2, // binary number without prefix
+ IoDec = 10, // decimal number without prefix
+ IoHex = 16, // hexadecimal number without prefix
+ IoArray = 32, // array of Unit(fixed size)
+ IoArrayRaw = 64, // raw array of Unit without Montgomery conversion
+ IoPrefix = 128, // append '0b'(bin) or '0x'(hex)
+ IoBinPrefix = IoBin | IoPrefix,
+ IoHexPrefix = IoHex | IoPrefix,
+ IoEcAffine = 0, // affine coordinate
+ IoEcCompY = 256, // 1-bit y representation of elliptic curve
+ IoSerialize = 512, // use MBS for 1-bit y
+ IoFixedSizeByteSeq = IoSerialize, // obsolete
+ IoEcProj = 1024, // projective or jacobi coordinate
+ IoSerializeHexStr = 2048 // printable hex string
+};
+
+namespace fp {
+
+const size_t UnitBitSize = sizeof(Unit) * 8;
+
+const size_t maxUnitSize = (MCL_MAX_BIT_SIZE + UnitBitSize - 1) / UnitBitSize;
+#define MCL_MAX_UNIT_SIZE ((MCL_MAX_BIT_SIZE + MCL_UNIT_BIT_SIZE - 1) / MCL_UNIT_BIT_SIZE)
+
+struct FpGenerator;
+struct Op;
+
+typedef void (*void1u)(Unit*);
+typedef void (*void2u)(Unit*, const Unit*);
+typedef void (*void2uI)(Unit*, const Unit*, Unit);
+typedef void (*void2uIu)(Unit*, const Unit*, Unit, const Unit*);
+typedef void (*void2uOp)(Unit*, const Unit*, const Op&);
+typedef void (*void3u)(Unit*, const Unit*, const Unit*);
+typedef void (*void4u)(Unit*, const Unit*, const Unit*, const Unit*);
+typedef int (*int2u)(Unit*, const Unit*);
+
+typedef Unit (*u1uII)(Unit*, Unit, Unit);
+typedef Unit (*u3u)(Unit*, const Unit*, const Unit*);
+
+/*
+ disable -Wcast-function-type
+ the number of arguments of some JIT functions is smaller than that of T
+*/
+template<class T, class S>
+T func_ptr_cast(S func)
+{
+ return reinterpret_cast<T>(reinterpret_cast<void*>(func));
+}
+struct Block {
+ const Unit *p; // pointer to original FpT.v_
+ size_t n;
+ Unit v_[maxUnitSize];
+};
+
+enum Mode {
+ FP_AUTO,
+ FP_GMP,
+ FP_GMP_MONT,
+ FP_LLVM,
+ FP_LLVM_MONT,
+ FP_XBYAK
+};
+
+enum PrimeMode {
+ PM_GENERIC = 0,
+ PM_NIST_P192,
+ PM_SECP256K1,
+ PM_NIST_P521
+};
+
+enum MaskMode {
+ NoMask = 0, // throw if greater or equal
+ SmallMask = 1, // 1-bit smaller mask if greater or equal
+ MaskAndMod = 2, // mask and substract if greater or equal
+ Mod = 3 // mod p
+};
+
+struct Op {
+ /*
+ don't change the layout of rp and p
+ asm code assumes &rp + 1 == p
+ */
+ Unit rp;
+ Unit p[maxUnitSize];
+ mpz_class mp;
+ uint32_t pmod4;
+ mcl::SquareRoot sq;
+ mcl::Modp modp;
+ Unit half[maxUnitSize]; // (p + 1) / 2
+ Unit oneRep[maxUnitSize]; // 1(=inv R if Montgomery)
+ /*
+ for Montgomery
+ one = 1
+ R = (1 << (N * sizeof(Unit) * 8)) % p
+ R2 = (R * R) % p
+ R3 = RR^3
+ */
+ Unit one[maxUnitSize];
+ Unit R2[maxUnitSize];
+ Unit R3[maxUnitSize];
+#ifdef MCL_USE_XBYAK
+ FpGenerator *fg;
+ mcl::Array<Unit> invTbl;
+#endif
+ void3u fp_addA_;
+ void3u fp_subA_;
+ void2u fp_negA_;
+ void3u fp_mulA_;
+ void2u fp_sqrA_;
+ void3u fp2_addA_;
+ void3u fp2_subA_;
+ void2u fp2_negA_;
+ void3u fp2_mulA_;
+ void2u fp2_sqrA_;
+ void3u fpDbl_addA_;
+ void3u fpDbl_subA_;
+ void3u fpDbl_mulPreA_;
+ void2u fpDbl_sqrPreA_;
+ void2u fpDbl_modA_;
+ void3u fp2Dbl_mulPreA_;
+ void2u fp2Dbl_sqrPreA_;
+ size_t maxN;
+ size_t N;
+ size_t bitSize;
+ bool (*fp_isZero)(const Unit*);
+ void1u fp_clear;
+ void2u fp_copy;
+ void2u fp_shr1;
+ void3u fp_neg;
+ void4u fp_add;
+ void4u fp_sub;
+ void4u fp_mul;
+ void3u fp_sqr;
+ void2uOp fp_invOp;
+ void2uIu fp_mulUnit; // fpN1_mod + fp_mulUnitPre
+
+ void3u fpDbl_mulPre;
+ void2u fpDbl_sqrPre;
+ int2u fp_preInv;
+ void2uI fp_mulUnitPre; // z[N + 1] = x[N] * y
+ void3u fpN1_mod; // y[N] = x[N + 1] % p[N]
+
+ void4u fpDbl_add;
+ void4u fpDbl_sub;
+ void3u fpDbl_mod;
+
+ u3u fp_addPre; // without modulo p
+ u3u fp_subPre; // without modulo p
+ u3u fpDbl_addPre;
+ u3u fpDbl_subPre;
+ /*
+ for Fp2 = F[u] / (u^2 + 1)
+ x = a + bu
+ */
+ int xi_a; // xi = xi_a + u
+ void4u fp2_mulNF;
+ void2u fp2_inv;
+ void2u fp2_mul_xiA_;
+ uint32_t (*hash)(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);
+
+ PrimeMode primeMode;
+ bool isFullBit; // true if bitSize % uniSize == 0
+ bool isMont; // true if use Montgomery
+ bool isFastMod; // true if modulo is fast
+
+ Op()
+ {
+ clear();
+ }
+ ~Op()
+ {
+#ifdef MCL_USE_XBYAK
+ destroyFpGenerator(fg);
+#endif
+ }
+ void clear()
+ {
+ rp = 0;
+ memset(p, 0, sizeof(p));
+ mp = 0;
+ pmod4 = 0;
+ sq.clear();
+ // fg is not set
+ memset(half, 0, sizeof(half));
+ memset(oneRep, 0, sizeof(oneRep));
+ memset(one, 0, sizeof(one));
+ memset(R2, 0, sizeof(R2));
+ memset(R3, 0, sizeof(R3));
+#ifdef MCL_USE_XBYAK
+ invTbl.clear();
+#endif
+ fp_addA_ = 0;
+ fp_subA_ = 0;
+ fp_negA_ = 0;
+ fp_mulA_ = 0;
+ fp_sqrA_ = 0;
+ fp2_addA_ = 0;
+ fp2_subA_ = 0;
+ fp2_negA_ = 0;
+ fp2_mulA_ = 0;
+ fp2_sqrA_ = 0;
+ fpDbl_addA_ = 0;
+ fpDbl_subA_ = 0;
+ fpDbl_mulPreA_ = 0;
+ fpDbl_sqrPreA_ = 0;
+ fpDbl_modA_ = 0;
+ fp2Dbl_mulPreA_ = 0;
+ fp2Dbl_sqrPreA_ = 0;
+ maxN = 0;
+ N = 0;
+ bitSize = 0;
+ fp_isZero = 0;
+ fp_clear = 0;
+ fp_copy = 0;
+ fp_shr1 = 0;
+ fp_neg = 0;
+ fp_add = 0;
+ fp_sub = 0;
+ fp_mul = 0;
+ fp_sqr = 0;
+ fp_invOp = 0;
+ fp_mulUnit = 0;
+
+ fpDbl_mulPre = 0;
+ fpDbl_sqrPre = 0;
+ fp_preInv = 0;
+ fp_mulUnitPre = 0;
+ fpN1_mod = 0;
+
+ fpDbl_add = 0;
+ fpDbl_sub = 0;
+ fpDbl_mod = 0;
+
+ fp_addPre = 0;
+ fp_subPre = 0;
+ fpDbl_addPre = 0;
+ fpDbl_subPre = 0;
+
+ xi_a = 0;
+ fp2_mulNF = 0;
+ fp2_inv = 0;
+ fp2_mul_xiA_ = 0;
+
+ primeMode = PM_GENERIC;
+ isFullBit = false;
+ isMont = false;
+ isFastMod = false;
+ hash = 0;
+ }
+ void fromMont(Unit* y, const Unit *x) const
+ {
+ /*
+ M(x, y) = xyR^-1
+ y = M(x, 1) = xR^-1
+ */
+ fp_mul(y, x, one, p);
+ }
+ void toMont(Unit* y, const Unit *x) const
+ {
+ /*
+ y = M(x, R2) = xR^2 R^-1 = xR
+ */
+ fp_mul(y, x, R2, p);
+ }
+ bool init(const mpz_class& p, size_t maxBitSize, int xi_a, Mode mode, size_t mclMaxBitSize = MCL_MAX_BIT_SIZE);
+#ifdef MCL_USE_XBYAK
+ static FpGenerator* createFpGenerator();
+ static void destroyFpGenerator(FpGenerator *fg);
+#endif
+private:
+ Op(const Op&);
+ void operator=(const Op&);
+};
+
+inline const char* getIoSeparator(int ioMode)
+{
+ return (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr)) ? "" : " ";
+}
+
+inline void dump(const char *s, size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ printf("%02x ", (uint8_t)s[i]);
+ }
+ printf("\n");
+}
+
+#ifndef CYBOZU_DONT_USE_STRING
+int detectIoMode(int ioMode, const std::ios_base& ios);
+
+inline void dump(const std::string& s)
+{
+ dump(s.c_str(), s.size());
+}
+#endif
+
+} } // mcl::fp
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/operator.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/operator.hpp
new file mode 100644
index 000000000..e9bc506df
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/operator.hpp
@@ -0,0 +1,177 @@
+#pragma once
+/**
+ @file
+ @brief operator class
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/op.hpp>
+#include <mcl/util.hpp>
+#ifdef _MSC_VER
+ #ifndef MCL_FORCE_INLINE
+ #define MCL_FORCE_INLINE __forceinline
+ #endif
+ #pragma warning(push)
+ #pragma warning(disable : 4714)
+#else
+ #ifndef MCL_FORCE_INLINE
+ #define MCL_FORCE_INLINE __attribute__((always_inline))
+ #endif
+#endif
+
+namespace mcl { namespace fp {
+
+template<class T>
+struct Empty {};
+
+/*
+ T must have add, sub, mul, inv, neg
+*/
+template<class T, class E = Empty<T> >
+struct Operator : public E {
+ template<class S> MCL_FORCE_INLINE T& operator+=(const S& rhs) { T::add(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
+ template<class S> MCL_FORCE_INLINE T& operator-=(const S& rhs) { T::sub(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
+ template<class S> friend MCL_FORCE_INLINE T operator+(const T& a, const S& b) { T c; T::add(c, a, b); return c; }
+ template<class S> friend MCL_FORCE_INLINE T operator-(const T& a, const S& b) { T c; T::sub(c, a, b); return c; }
+ template<class S> MCL_FORCE_INLINE T& operator*=(const S& rhs) { T::mul(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
+ template<class S> friend MCL_FORCE_INLINE T operator*(const T& a, const S& b) { T c; T::mul(c, a, b); return c; }
+ MCL_FORCE_INLINE T& operator/=(const T& rhs) { T c; T::inv(c, rhs); T::mul(static_cast<T&>(*this), static_cast<const T&>(*this), c); return static_cast<T&>(*this); }
+ static MCL_FORCE_INLINE void div(T& c, const T& a, const T& b) { T t; T::inv(t, b); T::mul(c, a, t); }
+ friend MCL_FORCE_INLINE T operator/(const T& a, const T& b) { T c; T::inv(c, b); c *= a; return c; }
+ MCL_FORCE_INLINE T operator-() const { T c; T::neg(c, static_cast<const T&>(*this)); return c; }
+ template<class tag2, size_t maxBitSize2, template<class _tag, size_t _maxBitSize> class FpT>
+ static void pow(T& z, const T& x, const FpT<tag2, maxBitSize2>& y)
+ {
+ fp::Block b;
+ y.getBlock(b);
+ powArray(z, x, b.p, b.n, false, false);
+ }
+ template<class tag2, size_t maxBitSize2, template<class _tag, size_t _maxBitSize> class FpT>
+ static void powGeneric(T& z, const T& x, const FpT<tag2, maxBitSize2>& y)
+ {
+ fp::Block b;
+ y.getBlock(b);
+ powArrayBase(z, x, b.p, b.n, false, false);
+ }
+ template<class tag2, size_t maxBitSize2, template<class _tag, size_t _maxBitSize> class FpT>
+ static void powCT(T& z, const T& x, const FpT<tag2, maxBitSize2>& y)
+ {
+ fp::Block b;
+ y.getBlock(b);
+ powArray(z, x, b.p, b.n, false, true);
+ }
+ static void pow(T& z, const T& x, int64_t y)
+ {
+ const uint64_t u = fp::abs_(y);
+#if MCL_SIZEOF_UNIT == 8
+ powArray(z, x, &u, 1, y < 0, false);
+#else
+ uint32_t ua[2] = { uint32_t(u), uint32_t(u >> 32) };
+ size_t un = ua[1] ? 2 : 1;
+ powArray(z, x, ua, un, y < 0, false);
+#endif
+ }
+ static void pow(T& z, const T& x, const mpz_class& y)
+ {
+ powArray(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0, false);
+ }
+ static void powGeneric(T& z, const T& x, const mpz_class& y)
+ {
+ powArrayBase(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0, false);
+ }
+ static void powCT(T& z, const T& x, const mpz_class& y)
+ {
+ powArray(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0, true);
+ }
+ static void setPowArrayGLV(void f(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime))
+ {
+ powArrayGLV = f;
+ }
+private:
+ static void (*powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime);
+ static void powArray(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime)
+ {
+ if (powArrayGLV && (constTime || yn > 1)) {
+ powArrayGLV(z, x, y, yn, isNegative, constTime);
+ return;
+ }
+ powArrayBase(z, x, y, yn, isNegative, constTime);
+ }
+ static void powArrayBase(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime)
+ {
+ T tmp;
+ const T *px = &x;
+ if (&z == &x) {
+ tmp = x;
+ px = &tmp;
+ }
+ z = 1;
+ fp::powGeneric(z, *px, y, yn, T::mul, T::sqr, (void (*)(T&, const T&))0, constTime ? T::BaseFp::getBitSize() : 0);
+ if (isNegative) {
+ T::inv(z, z);
+ }
+ }
+};
+
+template<class T, class E>
+void (*Operator<T, E>::powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime);
+
+/*
+ T must have save and load
+*/
+template<class T, class E = Empty<T> >
+struct Serializable : public E {
+ void setStr(bool *pb, const char *str, int ioMode = 0)
+ {
+ size_t len = strlen(str);
+ size_t n = deserialize(str, len, ioMode);
+ *pb = n > 0 && n == len;
+ }
+ // return strlen(buf) if success else 0
+ size_t getStr(char *buf, size_t maxBufSize, int ioMode = 0) const
+ {
+ size_t n = serialize(buf, maxBufSize, ioMode);
+ if (n == 0 || n == maxBufSize - 1) return 0;
+ buf[n] = '\0';
+ return n;
+ }
+#ifndef CYBOZU_DONT_USE_STRING
+ void setStr(const std::string& str, int ioMode = 0)
+ {
+ cybozu::StringInputStream is(str);
+ static_cast<T&>(*this).load(is, ioMode);
+ }
+ void getStr(std::string& str, int ioMode = 0) const
+ {
+ str.clear();
+ cybozu::StringOutputStream os(str);
+ static_cast<const T&>(*this).save(os, ioMode);
+ }
+ std::string getStr(int ioMode = 0) const
+ {
+ std::string str;
+ getStr(str, ioMode);
+ return str;
+ }
+#endif
+ // return written bytes
+ size_t serialize(void *buf, size_t maxBufSize, int ioMode = IoSerialize) const
+ {
+ cybozu::MemoryOutputStream os(buf, maxBufSize);
+ bool b;
+ static_cast<const T&>(*this).save(&b, os, ioMode);
+ return b ? os.getPos() : 0;
+ }
+ // return read bytes
+ size_t deserialize(const void *buf, size_t bufSize, int ioMode = IoSerialize)
+ {
+ cybozu::MemoryInputStream is(buf, bufSize);
+ bool b;
+ static_cast<T&>(*this).load(&b, is, ioMode);
+ return b ? is.getPos() : 0;
+ }
+};
+
+} } // mcl::fp
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/paillier.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/paillier.hpp
new file mode 100644
index 000000000..03e44cb16
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/paillier.hpp
@@ -0,0 +1,84 @@
+#pragma once
+/**
+ @file
+ @brief paillier encryption
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/gmp_util.hpp>
+
+namespace mcl { namespace paillier {
+
+class PublicKey {
+ size_t primeBitSize;
+ mpz_class g;
+ mpz_class n;
+ mpz_class n2;
+public:
+ PublicKey() : primeBitSize(0) {}
+ void init(size_t _primeBitSize, const mpz_class& _n)
+ {
+ primeBitSize = _primeBitSize;
+ n = _n;
+ g = 1 + _n;
+ n2 = _n * _n;
+ }
+ void enc(mpz_class& c, const mpz_class& m, mcl::fp::RandGen rg = mcl::fp::RandGen()) const
+ {
+ if (rg.isZero()) rg = mcl::fp::RandGen::get();
+ if (primeBitSize == 0) throw cybozu::Exception("paillier:PublicKey:not init");
+ mpz_class r;
+ mcl::gmp::getRand(r, primeBitSize, rg);
+ mpz_class a, b;
+ mcl::gmp::powMod(a, g, m, n2);
+ mcl::gmp::powMod(b, r, n, n2);
+ c = (a * b) % n2;
+ }
+ /*
+ additive homomorphic encryption
+ cz = cx + cy
+ */
+ void add(mpz_class& cz, mpz_class& cx, mpz_class& cy) const
+ {
+ cz = (cx * cy) % n2;
+ }
+};
+
+class SecretKey {
+ size_t primeBitSize;
+ mpz_class n;
+ mpz_class n2;
+ mpz_class lambda;
+ mpz_class invLambda;
+public:
+ SecretKey() : primeBitSize(0) {}
+ /*
+ the size of prime is half of bitSize
+ */
+ void init(size_t bitSize, mcl::fp::RandGen rg = mcl::fp::RandGen())
+ {
+ if (rg.isZero()) rg = mcl::fp::RandGen::get();
+ primeBitSize = bitSize / 2;
+ mpz_class p, q;
+ mcl::gmp::getRandPrime(p, primeBitSize, rg);
+ mcl::gmp::getRandPrime(q, primeBitSize, rg);
+ lambda = (p - 1) * (q - 1);
+ n = p * q;
+ n2 = n * n;
+ mcl::gmp::invMod(invLambda, lambda, n);
+ }
+ void getPublicKey(PublicKey& pub) const
+ {
+ pub.init(primeBitSize, n);
+ }
+ void dec(mpz_class& m, const mpz_class& c) const
+ {
+ mpz_class L;
+ mcl::gmp::powMod(L, c, lambda, n2);
+ L = ((L - 1) / n) % n;
+ m = (L * invLambda) % n;
+ }
+};
+
+} } // mcl::paillier
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/randgen.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/randgen.hpp
new file mode 100644
index 000000000..30502fc10
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/randgen.hpp
@@ -0,0 +1,156 @@
+#pragma once
+/**
+ @file
+ @brief definition of Op
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#ifdef MCL_DONT_USE_CSPRNG
+
+// nothing
+
+#elif defined(MCL_USE_WEB_CRYPTO_API)
+#include <emscripten.h>
+
+namespace mcl {
+struct RandomGeneratorJS {
+ void read(bool *pb, void *buf, uint32_t byteSize)
+ {
+ // cf. https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
+ if (byteSize > 65536) {
+ *pb = false;
+ return;
+ }
+ // use crypto.getRandomValues
+ EM_ASM({Module.cryptoGetRandomValues($0, $1)}, buf, byteSize);
+ *pb = true;
+ }
+};
+} // mcl
+
+#else
+#include <cybozu/random_generator.hpp>
+#if 0 // #if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11
+#include <random>
+#endif
+#endif
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable : 4521)
+#endif
+namespace mcl { namespace fp {
+
+namespace local {
+
+template<class RG>
+uint32_t readWrapper(void *self, void *buf, uint32_t byteSize)
+{
+ bool b;
+ reinterpret_cast<RG*>(self)->read(&b, (uint8_t*)buf, byteSize);
+ if (b) return byteSize;
+ return 0;
+}
+
+#if 0 // #if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11
+template<>
+inline uint32_t readWrapper<std::random_device>(void *self, void *buf, uint32_t byteSize)
+{
+ const uint32_t keep = byteSize;
+ std::random_device& rg = *reinterpret_cast<std::random_device*>(self);
+ uint8_t *p = reinterpret_cast<uint8_t*>(buf);
+ uint32_t v;
+ while (byteSize >= 4) {
+ v = rg();
+ memcpy(p, &v, 4);
+ p += 4;
+ byteSize -= 4;
+ }
+ if (byteSize > 0) {
+ v = rg();
+ memcpy(p, &v, byteSize);
+ }
+ return keep;
+}
+#endif
+} // local
+/*
+ wrapper of cryptographically secure pseudo random number generator
+*/
+class RandGen {
+ typedef uint32_t (*readFuncType)(void *self, void *buf, uint32_t byteSize);
+ void *self_;
+ readFuncType readFunc_;
+public:
+ RandGen() : self_(0), readFunc_(0) {}
+ RandGen(void *self, readFuncType readFunc) : self_(self) , readFunc_(readFunc) {}
+ RandGen(const RandGen& rhs) : self_(rhs.self_), readFunc_(rhs.readFunc_) {}
+ RandGen(RandGen& rhs) : self_(rhs.self_), readFunc_(rhs.readFunc_) {}
+ RandGen& operator=(const RandGen& rhs)
+ {
+ self_ = rhs.self_;
+ readFunc_ = rhs.readFunc_;
+ return *this;
+ }
+ template<class RG>
+ RandGen(RG& rg)
+ : self_(reinterpret_cast<void*>(&rg))
+ , readFunc_(local::readWrapper<RG>)
+ {
+ }
+ void read(bool *pb, void *out, size_t byteSize)
+ {
+ uint32_t size = readFunc_(self_, out, static_cast<uint32_t>(byteSize));
+ *pb = size == byteSize;
+ }
+#ifdef MCL_DONT_USE_CSPRNG
+ bool isZero() const { return false; } /* return false to avoid copying default rg */
+#else
+ bool isZero() const { return self_ == 0 && readFunc_ == 0; }
+#endif
+ static RandGen& getDefaultRandGen()
+ {
+#ifdef MCL_DONT_USE_CSPRNG
+ static RandGen wrg;
+#elif defined(MCL_USE_WEB_CRYPTO_API)
+ static mcl::RandomGeneratorJS rg;
+ static RandGen wrg(rg);
+#else
+ static cybozu::RandomGenerator rg;
+ static RandGen wrg(rg);
+#endif
+ return wrg;
+ }
+ static RandGen& get()
+ {
+ static RandGen wrg(getDefaultRandGen());
+ return wrg;
+ }
+ /*
+ rg must be thread safe
+ rg.read(void *buf, size_t byteSize);
+ */
+ static void setRandGen(const RandGen& rg)
+ {
+ get() = rg;
+ }
+ /*
+ set rand function
+ if self and readFunc are NULL then set default rand function
+ */
+ static void setRandFunc(void *self, readFuncType readFunc)
+ {
+ if (self == 0 && readFunc == 0) {
+ setRandGen(getDefaultRandGen());
+ } else {
+ RandGen rg(self, readFunc);
+ setRandGen(rg);
+ }
+ }
+};
+
+} } // mcl::fp
+
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/she.h b/vendor/github.com/byzantine-lab/mcl/include/mcl/she.h
new file mode 100644
index 000000000..60b399c65
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/she.h
@@ -0,0 +1,270 @@
+#pragma once
+/**
+ @file
+ @brief C api of somewhat homomorphic encryption with one-time multiplication, based on prime-order pairings
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <mcl/bn.h>
+
+#ifdef _MSC_VER
+#ifdef MCLSHE_DLL_EXPORT
+#define MCLSHE_DLL_API __declspec(dllexport)
+#else
+#define MCLSHE_DLL_API __declspec(dllimport)
+#ifndef MCLSHE_NO_AUTOLINK
+ #if MCLBN_FP_UNIT_SIZE == 4
+ #pragma comment(lib, "mclshe256.lib")
+ #elif MCLBN_FP_UNIT_SIZE == 6
+ #pragma comment(lib, "mclshe384.lib")
+ #else
+ #pragma comment(lib, "mclshe512.lib")
+ #endif
+#endif
+#endif
+#else
+#ifdef __EMSCRIPTEN__
+ #define MCLSHE_DLL_API __attribute__((used))
+#elif defined(__wasm__)
+ #define MCLSHE_DLL_API __attribute__((visibility("default")))
+#else
+ #define MCLSHE_DLL_API
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ mclBnFr x;
+ mclBnFr y;
+} sheSecretKey;
+
+typedef struct {
+ mclBnG1 xP;
+ mclBnG2 yQ;
+} shePublicKey;
+
+struct shePrecomputedPublicKey;
+
+typedef struct {
+ mclBnG1 S;
+ mclBnG1 T;
+} sheCipherTextG1;
+
+typedef struct {
+ mclBnG2 S;
+ mclBnG2 T;
+} sheCipherTextG2;
+
+typedef struct {
+ mclBnGT g[4];
+} sheCipherTextGT;
+
+typedef struct {
+ mclBnFr d[4];
+} sheZkpBin;
+
+typedef struct {
+ mclBnFr d[4];
+} sheZkpEq;
+
+typedef struct {
+ mclBnFr d[7];
+} sheZkpBinEq;
+/*
+ initialize this library
+ call this once before using the other functions
+ @param curve [in] enum value defined in mcl/bn.h
+ @param compiledTimeVar [in] specify MCLBN_COMPILED_TIME_VAR,
+ which macro is used to make sure that the values
+ are the same when the library is built and used
+ @return 0 if success
+ @note sheInit() is thread safe and serialized if it is called simultaneously
+ but don't call it while using other functions.
+*/
+MCLSHE_DLL_API int sheInit(int curve, int compiledTimeVar);
+
+// return written byte size if success else 0
+MCLSHE_DLL_API mclSize sheSecretKeySerialize(void *buf, mclSize maxBufSize, const sheSecretKey *sec);
+MCLSHE_DLL_API mclSize shePublicKeySerialize(void *buf, mclSize maxBufSize, const shePublicKey *pub);
+MCLSHE_DLL_API mclSize sheCipherTextG1Serialize(void *buf, mclSize maxBufSize, const sheCipherTextG1 *c);
+MCLSHE_DLL_API mclSize sheCipherTextG2Serialize(void *buf, mclSize maxBufSize, const sheCipherTextG2 *c);
+MCLSHE_DLL_API mclSize sheCipherTextGTSerialize(void *buf, mclSize maxBufSize, const sheCipherTextGT *c);
+MCLSHE_DLL_API mclSize sheZkpBinSerialize(void *buf, mclSize maxBufSize, const sheZkpBin *zkp);
+MCLSHE_DLL_API mclSize sheZkpEqSerialize(void *buf, mclSize maxBufSize, const sheZkpEq *zkp);
+MCLSHE_DLL_API mclSize sheZkpBinEqSerialize(void *buf, mclSize maxBufSize, const sheZkpBinEq *zkp);
+
+// return read byte size if sucess else 0
+MCLSHE_DLL_API mclSize sheSecretKeyDeserialize(sheSecretKey* sec, const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize shePublicKeyDeserialize(shePublicKey* pub, const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize sheCipherTextG1Deserialize(sheCipherTextG1* c, const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize sheCipherTextG2Deserialize(sheCipherTextG2* c, const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize sheCipherTextGTDeserialize(sheCipherTextGT* c, const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize sheZkpBinDeserialize(sheZkpBin* zkp, const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize sheZkpEqDeserialize(sheZkpEq* zkp, const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize sheZkpBinEqDeserialize(sheZkpBinEq* zkp, const void *buf, mclSize bufSize);
+
+/*
+ set secretKey if system has /dev/urandom or CryptGenRandom
+ return 0 if success
+*/
+MCLSHE_DLL_API int sheSecretKeySetByCSPRNG(sheSecretKey *sec);
+
+MCLSHE_DLL_API void sheGetPublicKey(shePublicKey *pub, const sheSecretKey *sec);
+
+/*
+ make table to decode DLP
+ return 0 if success
+*/
+MCLSHE_DLL_API int sheSetRangeForDLP(mclSize hashSize);
+MCLSHE_DLL_API int sheSetRangeForG1DLP(mclSize hashSize);
+MCLSHE_DLL_API int sheSetRangeForG2DLP(mclSize hashSize);
+MCLSHE_DLL_API int sheSetRangeForGTDLP(mclSize hashSize);
+
+/*
+ set tryNum to decode DLP
+*/
+MCLSHE_DLL_API void sheSetTryNum(mclSize tryNum);
+
+/*
+ decode G1 via GT if use != 0
+ @note faster if tryNum >= 300
+*/
+MCLSHE_DLL_API void sheUseDecG1ViaGT(int use);
+/*
+ decode G2 via GT if use != 0
+ @note faster if tryNum >= 100
+*/
+MCLSHE_DLL_API void sheUseDecG2ViaGT(int use);
+/*
+ load table for DLP
+ return read size if success else 0
+*/
+MCLSHE_DLL_API mclSize sheLoadTableForG1DLP(const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize sheLoadTableForG2DLP(const void *buf, mclSize bufSize);
+MCLSHE_DLL_API mclSize sheLoadTableForGTDLP(const void *buf, mclSize bufSize);
+
+/*
+ save table for DLP
+ return written size if success else 0
+*/
+MCLSHE_DLL_API mclSize sheSaveTableForG1DLP(void *buf, mclSize maxBufSize);
+MCLSHE_DLL_API mclSize sheSaveTableForG2DLP(void *buf, mclSize maxBufSize);
+MCLSHE_DLL_API mclSize sheSaveTableForGTDLP(void *buf, mclSize maxBufSize);
+
+// return 0 if success
+MCLSHE_DLL_API int sheEncG1(sheCipherTextG1 *c, const shePublicKey *pub, mclInt m);
+MCLSHE_DLL_API int sheEncG2(sheCipherTextG2 *c, const shePublicKey *pub, mclInt m);
+MCLSHE_DLL_API int sheEncGT(sheCipherTextGT *c, const shePublicKey *pub, mclInt m);
+MCLSHE_DLL_API int shePrecomputedPublicKeyEncG1(sheCipherTextG1 *c, const shePrecomputedPublicKey *ppub, mclInt m);
+MCLSHE_DLL_API int shePrecomputedPublicKeyEncG2(sheCipherTextG2 *c, const shePrecomputedPublicKey *ppub, mclInt m);
+MCLSHE_DLL_API int shePrecomputedPublicKeyEncGT(sheCipherTextGT *c, const shePrecomputedPublicKey *ppub, mclInt m);
+
+/*
+ m must be 0 or 1
+*/
+MCLSHE_DLL_API int sheEncWithZkpBinG1(sheCipherTextG1 *c, sheZkpBin *zkp, const shePublicKey *pub, int m);
+MCLSHE_DLL_API int sheEncWithZkpBinG2(sheCipherTextG2 *c, sheZkpBin *zkp, const shePublicKey *pub, int m);
+MCLSHE_DLL_API int sheEncWithZkpBinEq(sheCipherTextG1 *c1, sheCipherTextG2 *c2, sheZkpBinEq *zkp, const shePublicKey *pub, int m);
+MCLSHE_DLL_API int shePrecomputedPublicKeyEncWithZkpBinG1(sheCipherTextG1 *c, sheZkpBin *zkp, const shePrecomputedPublicKey *ppub, int m);
+MCLSHE_DLL_API int shePrecomputedPublicKeyEncWithZkpBinG2(sheCipherTextG2 *c, sheZkpBin *zkp, const shePrecomputedPublicKey *ppub, int m);
+MCLSHE_DLL_API int shePrecomputedPublicKeyEncWithZkpBinEq(sheCipherTextG1 *c1, sheCipherTextG2 *c2, sheZkpBinEq *zkp, const shePrecomputedPublicKey *ppub, int m);
+
+/*
+ arbitary m
+*/
+MCLSHE_DLL_API int sheEncWithZkpEq(sheCipherTextG1 *c1, sheCipherTextG2 *c2, sheZkpEq *zkp, const shePublicKey *pub, mclInt m);
+MCLSHE_DLL_API int shePrecomputedPublicKeyEncWithZkpEq(sheCipherTextG1 *c1, sheCipherTextG2 *c2, sheZkpEq *zkp, const shePrecomputedPublicKey *ppub, mclInt m);
+
+/*
+ decode c and set m
+ return 0 if success
+*/
+MCLSHE_DLL_API int sheDecG1(mclInt *m, const sheSecretKey *sec, const sheCipherTextG1 *c);
+MCLSHE_DLL_API int sheDecG2(mclInt *m, const sheSecretKey *sec, const sheCipherTextG2 *c);
+MCLSHE_DLL_API int sheDecGT(mclInt *m, const sheSecretKey *sec, const sheCipherTextGT *c);
+/*
+ verify zkp
+ return 1 if valid
+*/
+MCLSHE_DLL_API int sheVerifyZkpBinG1(const shePublicKey *pub, const sheCipherTextG1 *c, const sheZkpBin *zkp);
+MCLSHE_DLL_API int sheVerifyZkpBinG2(const shePublicKey *pub, const sheCipherTextG2 *c, const sheZkpBin *zkp);
+MCLSHE_DLL_API int sheVerifyZkpEq(const shePublicKey *pub, const sheCipherTextG1 *c1, const sheCipherTextG2 *c2, const sheZkpEq *zkp);
+MCLSHE_DLL_API int sheVerifyZkpBinEq(const shePublicKey *pub, const sheCipherTextG1 *c1, const sheCipherTextG2 *c2, const sheZkpBinEq *zkp);
+MCLSHE_DLL_API int shePrecomputedPublicKeyVerifyZkpBinG1(const shePrecomputedPublicKey *ppub, const sheCipherTextG1 *c, const sheZkpBin *zkp);
+MCLSHE_DLL_API int shePrecomputedPublicKeyVerifyZkpBinG2(const shePrecomputedPublicKey *ppub, const sheCipherTextG2 *c, const sheZkpBin *zkp);
+MCLSHE_DLL_API int shePrecomputedPublicKeyVerifyZkpEq(const shePrecomputedPublicKey *ppub, const sheCipherTextG1 *c1, const sheCipherTextG2 *c2, const sheZkpEq *zkp);
+MCLSHE_DLL_API int shePrecomputedPublicKeyVerifyZkpBinEq(const shePrecomputedPublicKey *ppub, const sheCipherTextG1 *c1, const sheCipherTextG2 *c2, const sheZkpBinEq *zkp);
+/*
+ decode c via GT and set m
+ return 0 if success
+*/
+MCLSHE_DLL_API int sheDecG1ViaGT(mclInt *m, const sheSecretKey *sec, const sheCipherTextG1 *c);
+MCLSHE_DLL_API int sheDecG2ViaGT(mclInt *m, const sheSecretKey *sec, const sheCipherTextG2 *c);
+
+/*
+ return 1 if dec(c) == 0
+*/
+MCLSHE_DLL_API int sheIsZeroG1(const sheSecretKey *sec, const sheCipherTextG1 *c);
+MCLSHE_DLL_API int sheIsZeroG2(const sheSecretKey *sec, const sheCipherTextG2 *c);
+MCLSHE_DLL_API int sheIsZeroGT(const sheSecretKey *sec, const sheCipherTextGT *c);
+
+// return 0 if success
+// y = -x
+MCLSHE_DLL_API int sheNegG1(sheCipherTextG1 *y, const sheCipherTextG1 *x);
+MCLSHE_DLL_API int sheNegG2(sheCipherTextG2 *y, const sheCipherTextG2 *x);
+MCLSHE_DLL_API int sheNegGT(sheCipherTextGT *y, const sheCipherTextGT *x);
+
+// return 0 if success
+// z = x + y
+MCLSHE_DLL_API int sheAddG1(sheCipherTextG1 *z, const sheCipherTextG1 *x, const sheCipherTextG1 *y);
+MCLSHE_DLL_API int sheAddG2(sheCipherTextG2 *z, const sheCipherTextG2 *x, const sheCipherTextG2 *y);
+MCLSHE_DLL_API int sheAddGT(sheCipherTextGT *z, const sheCipherTextGT *x, const sheCipherTextGT *y);
+
+// return 0 if success
+// z = x - y
+MCLSHE_DLL_API int sheSubG1(sheCipherTextG1 *z, const sheCipherTextG1 *x, const sheCipherTextG1 *y);
+MCLSHE_DLL_API int sheSubG2(sheCipherTextG2 *z, const sheCipherTextG2 *x, const sheCipherTextG2 *y);
+MCLSHE_DLL_API int sheSubGT(sheCipherTextGT *z, const sheCipherTextGT *x, const sheCipherTextGT *y);
+
+// return 0 if success
+// z = x * y
+MCLSHE_DLL_API int sheMulG1(sheCipherTextG1 *z, const sheCipherTextG1 *x, mclInt y);
+MCLSHE_DLL_API int sheMulG2(sheCipherTextG2 *z, const sheCipherTextG2 *x, mclInt y);
+MCLSHE_DLL_API int sheMulGT(sheCipherTextGT *z, const sheCipherTextGT *x, mclInt y);
+
+// return 0 if success
+// z = x * y
+MCLSHE_DLL_API int sheMul(sheCipherTextGT *z, const sheCipherTextG1 *x, const sheCipherTextG2 *y);
+/*
+ sheMul(z, x, y) = sheMulML(z, x, y) + sheFinalExpGT(z)
+ @note
+ Mul(x1, y1) + ... + Mul(xn, yn) = finalExp(MulML(x1, y1) + ... + MulML(xn, yn))
+*/
+MCLSHE_DLL_API int sheMulML(sheCipherTextGT *z, const sheCipherTextG1 *x, const sheCipherTextG2 *y);
+MCLSHE_DLL_API int sheFinalExpGT(sheCipherTextGT *y, const sheCipherTextGT *x);
+
+// return 0 if success
+// rerandomize(c)
+MCLSHE_DLL_API int sheReRandG1(sheCipherTextG1 *c, const shePublicKey *pub);
+MCLSHE_DLL_API int sheReRandG2(sheCipherTextG2 *c, const shePublicKey *pub);
+MCLSHE_DLL_API int sheReRandGT(sheCipherTextGT *c, const shePublicKey *pub);
+
+// return 0 if success
+// y = convert(x)
+MCLSHE_DLL_API int sheConvertG1(sheCipherTextGT *y, const shePublicKey *pub, const sheCipherTextG1 *x);
+MCLSHE_DLL_API int sheConvertG2(sheCipherTextGT *y, const shePublicKey *pub, const sheCipherTextG2 *x);
+
+// return nonzero if success
+MCLSHE_DLL_API shePrecomputedPublicKey *shePrecomputedPublicKeyCreate();
+// call this function to avoid memory leak
+MCLSHE_DLL_API void shePrecomputedPublicKeyDestroy(shePrecomputedPublicKey *ppub);
+// return 0 if success
+MCLSHE_DLL_API int shePrecomputedPublicKeyInit(shePrecomputedPublicKey *ppub, const shePublicKey *pub);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/she.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/she.hpp
new file mode 100644
index 000000000..3ce361454
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/she.hpp
@@ -0,0 +1,1939 @@
+#pragma once
+/**
+ @file
+ @brief somewhat homomorphic encryption with one-time multiplication, based on prime-order pairings
+ @author MITSUNARI Shigeo(@herumi)
+ see https://github.com/herumi/mcl/blob/master/misc/she/she.pdf
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <cmath>
+#include <vector>
+#include <iosfwd>
+#ifndef MCLBN_FP_UNIT_SIZE
+ #define MCLBN_FP_UNIT_SIZE 4
+#endif
+#if MCLBN_FP_UNIT_SIZE == 4
+#include <mcl/bn256.hpp>
+#elif MCLBN_FP_UNIT_SIZE == 6
+#include <mcl/bn384.hpp>
+#elif MCLBN_FP_UNIT_SIZE == 8
+#include <mcl/bn512.hpp>
+#else
+ #error "MCLBN_FP_UNIT_SIZE must be 4, 6, or 8"
+#endif
+
+#include <mcl/window_method.hpp>
+#include <cybozu/endian.hpp>
+#include <cybozu/serializer.hpp>
+
+namespace mcl { namespace she {
+
+using namespace mcl::bn;
+
+namespace local {
+
+#ifndef MCLSHE_WIN_SIZE
+ #define MCLSHE_WIN_SIZE 10
+#endif
+static const size_t winSize = MCLSHE_WIN_SIZE;
+static const size_t defaultTryNum = 2048;
+
+struct KeyCount {
+ uint32_t key;
+ int32_t count; // power
+ bool operator<(const KeyCount& rhs) const
+ {
+ return key < rhs.key;
+ }
+ bool isSame(const KeyCount& rhs) const
+ {
+ return key == rhs.key && count == rhs.count;
+ }
+};
+
+template<class G, bool = true>
+struct InterfaceForHashTable : G {
+ static G& castG(InterfaceForHashTable& x) { return static_cast<G&>(x); }
+ static const G& castG(const InterfaceForHashTable& x) { return static_cast<const G&>(x); }
+ void clear() { clear(castG(*this)); }
+ void normalize() { normalize(castG(*this)); }
+ static bool isOdd(const G& P) { return P.y.isOdd(); }
+ static bool isZero(const G& P) { return P.isZero(); }
+ static bool isSameX(const G& P, const G& Q) { return P.x == Q.x; }
+ static uint32_t getHash(const G& P) { return uint32_t(*P.x.getUnit()); }
+ static void clear(G& P) { P.clear(); }
+ static void normalize(G& P) { P.normalize(); }
+ static void dbl(G& Q, const G& P) { G::dbl(Q, P); }
+ static void neg(G& Q, const G& P) { G::neg(Q, P); }
+ static void add(G& R, const G& P, const G& Q) { G::add(R, P, Q); }
+ template<class INT>
+ static void mul(G& Q, const G& P, const INT& x) { G::mul(Q, P, x); }
+};
+
+/*
+ treat Fp12 as EC
+ unitary inverse of (a, b) = (a, -b)
+ then b.a.a or -b.a.a is odd
+*/
+template<class G>
+struct InterfaceForHashTable<G, false> : G {
+ static G& castG(InterfaceForHashTable& x) { return static_cast<G&>(x); }
+ static const G& castG(const InterfaceForHashTable& x) { return static_cast<const G&>(x); }
+ void clear() { clear(castG(*this)); }
+ void normalize() { normalize(castG(*this)); }
+ static bool isOdd(const G& x) { return x.b.a.a.isOdd(); }
+ static bool isZero(const G& x) { return x.isOne(); }
+ static bool isSameX(const G& x, const G& Q) { return x.a == Q.a; }
+ static uint32_t getHash(const G& x) { return uint32_t(*x.getFp0()->getUnit()); }
+ static void clear(G& x) { x = 1; }
+ static void normalize(G&) { }
+ static void dbl(G& y, const G& x) { G::sqr(y, x); }
+ static void neg(G& Q, const G& P) { G::unitaryInv(Q, P); }
+ static void add(G& z, const G& x, const G& y) { G::mul(z, x, y); }
+ template<class INT>
+ static void mul(G& z, const G& x, const INT& y) { G::pow(z, x, y); }
+};
+
+template<class G>
+char GtoChar();
+template<>char GtoChar<bn::G1>() { return '1'; }
+template<>char GtoChar<bn::G2>() { return '2'; }
+template<>char GtoChar<bn::GT>() { return 'T'; }
+
+/*
+ HashTable<EC, true> or HashTable<Fp12, false>
+*/
+template<class G, bool isEC = true>
+class HashTable {
+ typedef InterfaceForHashTable<G, isEC> I;
+ typedef std::vector<KeyCount> KeyCountVec;
+ KeyCountVec kcv_;
+ G P_;
+ mcl::fp::WindowMethod<I> wm_;
+ G nextP_;
+ G nextNegP_;
+ size_t tryNum_;
+ void setWindowMethod()
+ {
+ const size_t bitSize = G::BaseFp::BaseFp::getBitSize();
+ wm_.init(static_cast<const I&>(P_), bitSize, local::winSize);
+ }
+public:
+ HashTable() : tryNum_(local::defaultTryNum) {}
+ bool operator==(const HashTable& rhs) const
+ {
+ if (kcv_.size() != rhs.kcv_.size()) return false;
+ for (size_t i = 0; i < kcv_.size(); i++) {
+ if (!kcv_[i].isSame(rhs.kcv_[i])) return false;
+ }
+ return P_ == rhs.P_ && nextP_ == rhs.nextP_;
+ }
+ bool operator!=(const HashTable& rhs) const { return !operator==(rhs); }
+ /*
+ compute log_P(xP) for |x| <= hashSize * tryNum
+ */
+ void init(const G& P, size_t hashSize, size_t tryNum = local::defaultTryNum)
+ {
+ if (hashSize == 0) {
+ kcv_.clear();
+ return;
+ }
+ if (hashSize >= 0x80000000u) throw cybozu::Exception("HashTable:init:hashSize is too large");
+ P_ = P;
+ tryNum_ = tryNum;
+ kcv_.resize(hashSize);
+ G xP;
+ I::clear(xP);
+ for (int i = 1; i <= (int)kcv_.size(); i++) {
+ I::add(xP, xP, P_);
+ I::normalize(xP);
+ kcv_[i - 1].key = I::getHash(xP);
+ kcv_[i - 1].count = I::isOdd(xP) ? i : -i;
+ }
+ nextP_ = xP;
+ I::dbl(nextP_, nextP_);
+ I::add(nextP_, nextP_, P_); // nextP = (hasSize * 2 + 1)P
+ I::neg(nextNegP_, nextP_); // nextNegP = -nextP
+ /*
+ ascending order of abs(count) for same key
+ */
+ std::stable_sort(kcv_.begin(), kcv_.end());
+ setWindowMethod();
+ }
+ void setTryNum(size_t tryNum)
+ {
+ this->tryNum_ = tryNum;
+ }
+ /*
+ log_P(xP)
+ find range which has same hash of xP in kcv_,
+ and detect it
+ */
+ int basicLog(G xP, bool *ok = 0) const
+ {
+ if (ok) *ok = true;
+ if (I::isZero(xP)) return 0;
+ typedef KeyCountVec::const_iterator Iter;
+ KeyCount kc;
+ I::normalize(xP);
+ kc.key = I::getHash(xP);
+ kc.count = 0;
+ std::pair<Iter, Iter> p = std::equal_range(kcv_.begin(), kcv_.end(), kc);
+ G Q;
+ I::clear(Q);
+ int prev = 0;
+ /*
+ check range which has same hash
+ */
+ while (p.first != p.second) {
+ int count = p.first->count;
+ int abs_c = std::abs(count);
+ assert(abs_c >= prev); // assume ascending order
+ bool neg = count < 0;
+ G T;
+// I::mul(T, P, abs_c - prev);
+ mulByWindowMethod(T, abs_c - prev);
+ I::add(Q, Q, T);
+ I::normalize(Q);
+ if (I::isSameX(Q, xP)) {
+ bool QisOdd = I::isOdd(Q);
+ bool xPisOdd = I::isOdd(xP);
+ if (QisOdd ^ xPisOdd ^ neg) return -count;
+ return count;
+ }
+ prev = abs_c;
+ ++p.first;
+ }
+ if (ok) {
+ *ok = false;
+ return 0;
+ }
+ throw cybozu::Exception("HashTable:basicLog:not found");
+ }
+ /*
+ compute log_P(xP)
+ call basicLog at most 2 * tryNum
+ */
+ int64_t log(const G& xP) const
+ {
+ bool ok;
+ int c = basicLog(xP, &ok);
+ if (ok) {
+ return c;
+ }
+ G posP = xP, negP = xP;
+ int64_t posCenter = 0;
+ int64_t negCenter = 0;
+ int64_t next = (int64_t)kcv_.size() * 2 + 1;
+ for (size_t i = 1; i < tryNum_; i++) {
+ I::add(posP, posP, nextNegP_);
+ posCenter += next;
+ c = basicLog(posP, &ok);
+ if (ok) {
+ return posCenter + c;
+ }
+ I::add(negP, negP, nextP_);
+ negCenter -= next;
+ c = basicLog(negP, &ok);
+ if (ok) {
+ return negCenter + c;
+ }
+ }
+ throw cybozu::Exception("HashTable:log:not found");
+ }
+ /*
+ remark
+ tryNum is not saved.
+ */
+ template<class OutputStream>
+ void save(OutputStream& os) const
+ {
+ cybozu::save(os, BN::param.cp.curveType);
+ cybozu::writeChar(os, GtoChar<G>());
+ cybozu::save(os, kcv_.size());
+ cybozu::write(os, &kcv_[0], sizeof(kcv_[0]) * kcv_.size());
+ P_.save(os);
+ }
+ size_t save(void *buf, size_t maxBufSize) const
+ {
+ cybozu::MemoryOutputStream os(buf, maxBufSize);
+ save(os);
+ return os.getPos();
+ }
+ /*
+ remark
+ tryNum is not set
+ */
+ template<class InputStream>
+ void load(InputStream& is)
+ {
+ int curveType;
+ cybozu::load(curveType, is);
+ if (curveType != BN::param.cp.curveType) throw cybozu::Exception("HashTable:bad curveType") << curveType;
+ char c = 0;
+ if (!cybozu::readChar(&c, is) || c != GtoChar<G>()) throw cybozu::Exception("HashTable:bad c") << (int)c;
+ size_t kcvSize;
+ cybozu::load(kcvSize, is);
+ kcv_.resize(kcvSize);
+ cybozu::read(&kcv_[0], sizeof(kcv_[0]) * kcvSize, is);
+ P_.load(is);
+ I::mul(nextP_, P_, (kcvSize * 2) + 1);
+ I::neg(nextNegP_, nextP_);
+ setWindowMethod();
+ }
+ size_t load(const void *buf, size_t bufSize)
+ {
+ cybozu::MemoryInputStream is(buf, bufSize);
+ load(is);
+ return is.getPos();
+ }
+ const mcl::fp::WindowMethod<I>& getWM() const { return wm_; }
+ /*
+ mul(x, P, y);
+ */
+ template<class T>
+ void mulByWindowMethod(G& x, const T& y) const
+ {
+ wm_.mul(static_cast<I&>(x), y);
+ }
+};
+
+template<class G>
+int log(const G& P, const G& xP)
+{
+ if (xP.isZero()) return 0;
+ if (xP == P) return 1;
+ G negT;
+ G::neg(negT, P);
+ if (xP == negT) return -1;
+ G T = P;
+ for (int i = 2; i < 100; i++) {
+ T += P;
+ if (xP == T) return i;
+ G::neg(negT, T);
+ if (xP == negT) return -i;
+ }
+ throw cybozu::Exception("she:log:not found");
+}
+
+} // mcl::she::local
+
+template<size_t dummyInpl = 0>
+struct SHET {
+ class SecretKey;
+ class PublicKey;
+ class PrecomputedPublicKey;
+ // additive HE
+ class CipherTextA; // = CipherTextG1 + CipherTextG2
+ class CipherTextGT; // multiplicative HE
+ class CipherText; // CipherTextA + CipherTextGT
+
+ static G1 P_;
+ static G2 Q_;
+ static GT ePQ_; // e(P, Q)
+ static std::vector<Fp6> Qcoeff_;
+ static local::HashTable<G1> PhashTbl_;
+ static local::HashTable<G2> QhashTbl_;
+ static mcl::fp::WindowMethod<G2> Qwm_;
+ typedef local::InterfaceForHashTable<GT, false> GTasEC;
+ static local::HashTable<GT, false> ePQhashTbl_;
+ static bool useDecG1ViaGT_;
+ static bool useDecG2ViaGT_;
+ static bool isG1only_;
+private:
+ template<class G>
+ class CipherTextAT : public fp::Serializable<CipherTextAT<G> > {
+ G S_, T_;
+ friend class SecretKey;
+ friend class PublicKey;
+ friend class PrecomputedPublicKey;
+ friend class CipherTextA;
+ friend class CipherTextGT;
+ bool isZero(const Fr& x) const
+ {
+ G xT;
+ G::mul(xT, T_, x);
+ return S_ == xT;
+ }
+ public:
+ const G& getS() const { return S_; }
+ const G& getT() const { return T_; }
+ void clear()
+ {
+ S_.clear();
+ T_.clear();
+ }
+ static void add(CipherTextAT& z, const CipherTextAT& x, const CipherTextAT& y)
+ {
+ /*
+ (S, T) + (S', T') = (S + S', T + T')
+ */
+ G::add(z.S_, x.S_, y.S_);
+ G::add(z.T_, x.T_, y.T_);
+ }
+ static void sub(CipherTextAT& z, const CipherTextAT& x, const CipherTextAT& y)
+ {
+ /*
+ (S, T) - (S', T') = (S - S', T - T')
+ */
+ G::sub(z.S_, x.S_, y.S_);
+ G::sub(z.T_, x.T_, y.T_);
+ }
+ // INT = int64_t or Fr
+ template<class INT>
+ static void mul(CipherTextAT& z, const CipherTextAT& x, const INT& y)
+ {
+ G::mul(z.S_, x.S_, y);
+ G::mul(z.T_, x.T_, y);
+ }
+ static void neg(CipherTextAT& y, const CipherTextAT& x)
+ {
+ G::neg(y.S_, x.S_);
+ G::neg(y.T_, x.T_);
+ }
+ void add(const CipherTextAT& c) { add(*this, *this, c); }
+ void sub(const CipherTextAT& c) { sub(*this, *this, c); }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
+ {
+ S_.load(pb, is, ioMode); if (!*pb) return;
+ T_.load(pb, is, ioMode);
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ S_.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ T_.save(pb, os, ioMode);
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("she:CipherTextA:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("she:CipherTextA:save");
+ }
+ friend std::istream& operator>>(std::istream& is, CipherTextAT& self)
+ {
+ self.load(is, fp::detectIoMode(G::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const CipherTextAT& self)
+ {
+ self.save(os, fp::detectIoMode(G::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const CipherTextAT& rhs) const
+ {
+ return S_ == rhs.S_ && T_ == rhs.T_;
+ }
+ bool operator!=(const CipherTextAT& rhs) const { return !operator==(rhs); }
+ };
+ /*
+ g1 = millerLoop(P1, Q)
+ g2 = millerLoop(P2, Q)
+ */
+ static void doubleMillerLoop(GT& g1, GT& g2, const G1& P1, const G1& P2, const G2& Q)
+ {
+#if 1
+ std::vector<Fp6> Qcoeff;
+ precomputeG2(Qcoeff, Q);
+ precomputedMillerLoop(g1, P1, Qcoeff);
+ precomputedMillerLoop(g2, P2, Qcoeff);
+#else
+ millerLoop(g1, P1, Q);
+ millerLoop(g2, P2, Q);
+#endif
+ }
+ static void finalExp4(GT out[4], const GT in[4])
+ {
+ for (int i = 0; i < 4; i++) {
+ finalExp(out[i], in[i]);
+ }
+ }
+ static void tensorProductML(GT g[4], const G1& S1, const G1& T1, const G2& S2, const G2& T2)
+ {
+ /*
+ (S1, T1) x (S2, T2) = (ML(S1, S2), ML(S1, T2), ML(T1, S2), ML(T1, T2))
+ */
+ doubleMillerLoop(g[0], g[2], S1, T1, S2);
+ doubleMillerLoop(g[1], g[3], S1, T1, T2);
+ }
+ static void tensorProduct(GT g[4], const G1& S1, const G1& T1, const G2& S2, const G2& T2)
+ {
+ /*
+ (S1, T1) x (S2, T2) = (e(S1, S2), e(S1, T2), e(T1, S2), e(T1, T2))
+ */
+ tensorProductML(g,S1, T1, S2,T2);
+ finalExp4(g, g);
+ }
+ template<class Tag, size_t n>
+ struct ZkpT : public fp::Serializable<ZkpT<Tag, n> > {
+ Fr d_[n];
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
+ {
+ for (size_t i = 0; i < n; i++) {
+ d_[i].load(pb, is, ioMode); if (!*pb) return;
+ }
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ d_[0].save(pb, os, ioMode); if (!*pb) return;
+ for (size_t i = 1; i < n; i++) {
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ d_[i].save(pb, os, ioMode);
+ }
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("she:ZkpT:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("she:ZkpT:save");
+ }
+ friend std::istream& operator>>(std::istream& is, ZkpT& self)
+ {
+ self.load(is, fp::detectIoMode(Fr::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const ZkpT& self)
+ {
+ self.save(os, fp::detectIoMode(Fr::getIoMode(), os));
+ return os;
+ }
+ };
+ struct ZkpBinTag;
+ struct ZkpEqTag; // d_[] = { c, sp, ss, sm }
+ struct ZkpBinEqTag; // d_[] = { d0, d1, sp0, sp1, ss, sp, sm }
+public:
+ /*
+ Zkp for m = 0 or 1
+ */
+ typedef ZkpT<ZkpBinTag, 4> ZkpBin;
+ /*
+ Zkp for decG1(c1) == decG2(c2)
+ */
+ typedef ZkpT<ZkpEqTag, 4> ZkpEq;
+ /*
+ Zkp for (m = 0 or 1) and decG1(c1) == decG2(c2)
+ */
+ typedef ZkpT<ZkpBinEqTag, 7> ZkpBinEq;
+
+ typedef CipherTextAT<G1> CipherTextG1;
+ typedef CipherTextAT<G2> CipherTextG2;
+
+ static void init(const mcl::CurveParam& cp = mcl::BN254, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum)
+ {
+ initPairing(cp);
+ hashAndMapToG1(P_, "0");
+ hashAndMapToG2(Q_, "0");
+ pairing(ePQ_, P_, Q_);
+ precomputeG2(Qcoeff_, Q_);
+ setRangeForDLP(hashSize);
+ useDecG1ViaGT_ = false;
+ useDecG2ViaGT_ = false;
+ isG1only_ = false;
+ setTryNum(tryNum);
+ }
+ static void init(size_t hashSize, size_t tryNum = local::defaultTryNum)
+ {
+ init(mcl::BN254, hashSize, tryNum);
+ }
+ /*
+ standard lifted ElGamal encryption
+ */
+ static void initG1only(const mcl::EcParam& para, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum)
+ {
+ Fp::init(para.p);
+ Fr::init(para.n);
+ G1::init(para.a, para.b);
+ const Fp x0(para.gx);
+ const Fp y0(para.gy);
+ P_.set(x0, y0);
+
+ setRangeForG1DLP(hashSize);
+ useDecG1ViaGT_ = false;
+ useDecG2ViaGT_ = false;
+ isG1only_ = true;
+ setTryNum(tryNum);
+ }
+ /*
+ set range for G1-DLP
+ */
+ static void setRangeForG1DLP(size_t hashSize)
+ {
+ PhashTbl_.init(P_, hashSize);
+ }
+ /*
+ set range for G2-DLP
+ */
+ static void setRangeForG2DLP(size_t hashSize)
+ {
+ QhashTbl_.init(Q_, hashSize);
+ }
+ /*
+ set range for GT-DLP
+ */
+ static void setRangeForGTDLP(size_t hashSize)
+ {
+ ePQhashTbl_.init(ePQ_, hashSize);
+ }
+ /*
+ set range for G1/G2/GT DLP
+ decode message m for |m| <= hasSize * tryNum
+ decode time = O(log(hasSize) * tryNum)
+ */
+ static void setRangeForDLP(size_t hashSize)
+ {
+ setRangeForG1DLP(hashSize);
+ setRangeForG2DLP(hashSize);
+ setRangeForGTDLP(hashSize);
+ }
+ static void setTryNum(size_t tryNum)
+ {
+ PhashTbl_.setTryNum(tryNum);
+ QhashTbl_.setTryNum(tryNum);
+ ePQhashTbl_.setTryNum(tryNum);
+ }
+ static void useDecG1ViaGT(bool use = true)
+ {
+ useDecG1ViaGT_ = use;
+ }
+ static void useDecG2ViaGT(bool use = true)
+ {
+ useDecG2ViaGT_ = use;
+ }
+ /*
+ only one element is necessary for each G1 and G2.
+ this is better than David Mandell Freeman's algorithm
+ */
+ class SecretKey : public fp::Serializable<SecretKey> {
+ Fr x_, y_;
+ void getPowOfePQ(GT& v, const CipherTextGT& c) const
+ {
+ /*
+ (s, t, u, v) := (e(S, S'), e(S, T'), e(T, S'), e(T, T'))
+ s v^(xy) / (t^y u^x) = s (v^x / t) ^ y / u^x
+ = e(P, Q)^(mm')
+ */
+ GT t, u;
+ GT::unitaryInv(t, c.g_[1]);
+ GT::unitaryInv(u, c.g_[2]);
+ GT::pow(v, c.g_[3], x_);
+ v *= t;
+ GT::pow(v, v, y_);
+ GT::pow(u, u, x_);
+ v *= u;
+ v *= c.g_[0];
+ }
+ public:
+ void setByCSPRNG()
+ {
+ x_.setRand();
+ if (!isG1only_) y_.setRand();
+ }
+ /*
+ set xP and yQ
+ */
+ void getPublicKey(PublicKey& pub) const
+ {
+ pub.set(x_, y_);
+ }
+#if 0
+ // log_x(y)
+ int log(const GT& x, const GT& y) const
+ {
+ if (y == 1) return 0;
+ if (y == x) return 1;
+ GT inv;
+ GT::unitaryInv(inv, x);
+ if (y == inv) return -1;
+ GT t = x;
+ for (int i = 2; i < 100; i++) {
+ t *= x;
+ if (y == t) return i;
+ GT::unitaryInv(inv, t);
+ if (y == inv) return -i;
+ }
+ throw cybozu::Exception("she:dec:log:not found");
+ }
+#endif
+ int64_t dec(const CipherTextG1& c) const
+ {
+ if (useDecG1ViaGT_) return decViaGT(c);
+ /*
+ S = mP + rxP
+ T = rP
+ R = S - xT = mP
+ */
+ G1 R;
+ G1::mul(R, c.T_, x_);
+ G1::sub(R, c.S_, R);
+ return PhashTbl_.log(R);
+ }
+ int64_t dec(const CipherTextG2& c) const
+ {
+ if (useDecG2ViaGT_) return decViaGT(c);
+ G2 R;
+ G2::mul(R, c.T_, y_);
+ G2::sub(R, c.S_, R);
+ return QhashTbl_.log(R);
+ }
+ int64_t dec(const CipherTextA& c) const
+ {
+ return dec(c.c1_);
+ }
+ int64_t dec(const CipherTextGT& c) const
+ {
+ GT v;
+ getPowOfePQ(v, c);
+ return ePQhashTbl_.log(v);
+// return log(g, v);
+ }
+ int64_t decViaGT(const CipherTextG1& c) const
+ {
+ G1 R;
+ G1::mul(R, c.T_, x_);
+ G1::sub(R, c.S_, R);
+ GT v;
+ pairing(v, R, Q_);
+ return ePQhashTbl_.log(v);
+ }
+ int64_t decViaGT(const CipherTextG2& c) const
+ {
+ G2 R;
+ G2::mul(R, c.T_, y_);
+ G2::sub(R, c.S_, R);
+ GT v;
+ pairing(v, P_, R);
+ return ePQhashTbl_.log(v);
+ }
+ int64_t dec(const CipherText& c) const
+ {
+ if (c.isMultiplied()) {
+ return dec(c.m_);
+ } else {
+ return dec(c.a_);
+ }
+ }
+ bool isZero(const CipherTextG1& c) const
+ {
+ return c.isZero(x_);
+ }
+ bool isZero(const CipherTextG2& c) const
+ {
+ return c.isZero(y_);
+ }
+ bool isZero(const CipherTextA& c) const
+ {
+ return c.c1_.isZero(x_);
+ }
+ bool isZero(const CipherTextGT& c) const
+ {
+ GT v;
+ getPowOfePQ(v, c);
+ return v.isOne();
+ }
+ bool isZero(const CipherText& c) const
+ {
+ if (c.isMultiplied()) {
+ return isZero(c.m_);
+ } else {
+ return isZero(c.a_);
+ }
+ }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
+ {
+ x_.load(pb, is, ioMode); if (!*pb) return;
+ if (!isG1only_) y_.load(pb, is, ioMode);
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ x_.save(pb, os, ioMode); if (!*pb) return;
+ if (isG1only_) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ y_.save(os, ioMode);
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("she:SecretKey:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("she:SecretKey:save");
+ }
+ friend std::istream& operator>>(std::istream& is, SecretKey& self)
+ {
+ self.load(is, fp::detectIoMode(Fr::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const SecretKey& self)
+ {
+ self.save(os, fp::detectIoMode(Fr::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const SecretKey& rhs) const
+ {
+ return x_ == rhs.x_ && (isG1only_ || y_ == rhs.y_);
+ }
+ bool operator!=(const SecretKey& rhs) const { return !operator==(rhs); }
+ };
+private:
+ /*
+ simple ElGamal encryptionfor G1 and G2
+ (S, T) = (m P + r xP, rP)
+ Pmul.mul(X, a) // X = a P
+ xPmul.mul(X, a) // X = a xP
+ use *encRand if encRand is not null
+ */
+ template<class G, class INT, class MulG, class I>
+ static void ElGamalEnc(G& S, G& T, const INT& m, const mcl::fp::WindowMethod<I>& Pmul, const MulG& xPmul, const Fr *encRand = 0)
+ {
+ Fr r;
+ if (encRand) {
+ r = *encRand;
+ } else {
+ r.setRand();
+ }
+ Pmul.mul(static_cast<I&>(T), r);
+ xPmul.mul(S, r); // S = r xP
+ if (m == 0) return;
+ G C;
+ Pmul.mul(static_cast<I&>(C), m);
+ S += C;
+ }
+ /*
+ https://github.com/herumi/mcl/blob/master/misc/she/nizkp.pdf
+
+ encRand is a random value used for ElGamalEnc()
+ d[1-m] ; rand
+ s[1-m] ; rand
+ R[0][1-m] = s[1-m] P - d[1-m] T
+ R[1][1-m] = s[1-m] xP - d[1-m] (S - (1-m) P)
+ r ; rand
+ R[0][m] = r P
+ R[1][m] = r xP
+ c = H(S, T, R[0][0], R[0][1], R[1][0], R[1][1])
+ d[m] = c - d[1-m]
+ s[m] = r + d[m] encRand
+ */
+ template<class G, class I, class MulG>
+ static void makeZkpBin(ZkpBin& zkp, const G& S, const G& T, const Fr& encRand, const G& P, int m, const mcl::fp::WindowMethod<I>& Pmul, const MulG& xPmul)
+ {
+ if (m != 0 && m != 1) throw cybozu::Exception("makeZkpBin:bad m") << m;
+ Fr *s = &zkp.d_[0];
+ Fr *d = &zkp.d_[2];
+ G R[2][2];
+ d[1-m].setRand();
+ s[1-m].setRand();
+ G T1, T2;
+ Pmul.mul(static_cast<I&>(T1), s[1-m]); // T1 = s[1-m] P
+ G::mul(T2, T, d[1-m]);
+ G::sub(R[0][1-m], T1, T2); // s[1-m] P - d[1-m]T
+ xPmul.mul(T1, s[1-m]); // T1 = s[1-m] xP
+ if (m == 0) {
+ G::sub(T2, S, P);
+ G::mul(T2, T2, d[1-m]);
+ } else {
+ G::mul(T2, S, d[1-m]);
+ }
+ G::sub(R[1][1-m], T1, T2); // s[1-m] xP - d[1-m](S - (1-m) P)
+ Fr r;
+ r.setRand();
+ Pmul.mul(static_cast<I&>(R[0][m]), r); // R[0][m] = r P
+ xPmul.mul(R[1][m], r); // R[1][m] = r xP
+ char buf[sizeof(G) * 2];
+ cybozu::MemoryOutputStream os(buf, sizeof(buf));
+ S.save(os);
+ T.save(os);
+ R[0][0].save(os);
+ R[0][1].save(os);
+ R[1][0].save(os);
+ R[1][1].save(os);
+ Fr c;
+ c.setHashOf(buf, os.getPos());
+ d[m] = c - d[1-m];
+ s[m] = r + d[m] * encRand;
+ }
+ /*
+ R[0][i] = s[i] P - d[i] T ; i = 0,1
+ R[1][0] = s[0] xP - d[0] S
+ R[1][1] = s[1] xP - d[1](S - P)
+ c = H(S, T, R[0][0], R[0][1], R[1][0], R[1][1])
+ c == d[0] + d[1]
+ */
+ template<class G, class I, class MulG>
+ static bool verifyZkpBin(const G& S, const G& T, const G& P, const ZkpBin& zkp, const mcl::fp::WindowMethod<I>& Pmul, const MulG& xPmul)
+ {
+ const Fr *s = &zkp.d_[0];
+ const Fr *d = &zkp.d_[2];
+ G R[2][2];
+ G T1, T2;
+ for (int i = 0; i < 2; i++) {
+ Pmul.mul(static_cast<I&>(T1), s[i]); // T1 = s[i] P
+ G::mul(T2, T, d[i]);
+ G::sub(R[0][i], T1, T2);
+ }
+ xPmul.mul(T1, s[0]); // T1 = s[0] xP
+ G::mul(T2, S, d[0]);
+ G::sub(R[1][0], T1, T2);
+ xPmul.mul(T1, s[1]); // T1 = x[1] xP
+ G::sub(T2, S, P);
+ G::mul(T2, T2, d[1]);
+ G::sub(R[1][1], T1, T2);
+ char buf[sizeof(G) * 2];
+ cybozu::MemoryOutputStream os(buf, sizeof(buf));
+ S.save(os);
+ T.save(os);
+ R[0][0].save(os);
+ R[0][1].save(os);
+ R[1][0].save(os);
+ R[1][1].save(os);
+ Fr c;
+ c.setHashOf(buf, os.getPos());
+ return c == d[0] + d[1];
+ }
+ /*
+ encRand1, encRand2 are random values use for ElGamalEnc()
+ */
+ template<class G1, class G2, class INT, class I1, class I2, class MulG1, class MulG2>
+ static void makeZkpEq(ZkpEq& zkp, G1& S1, G1& T1, G2& S2, G2& T2, const INT& m, const mcl::fp::WindowMethod<I1>& Pmul, const MulG1& xPmul, const mcl::fp::WindowMethod<I2>& Qmul, const MulG2& yQmul)
+ {
+ Fr p, s;
+ p.setRand();
+ s.setRand();
+ ElGamalEnc(S1, T1, m, Pmul, xPmul, &p);
+ ElGamalEnc(S2, T2, m, Qmul, yQmul, &s);
+ Fr rp, rs, rm;
+ rp.setRand();
+ rs.setRand();
+ rm.setRand();
+ G1 R1, R2;
+ G2 R3, R4;
+ ElGamalEnc(R1, R2, rm, Pmul, xPmul, &rp);
+ ElGamalEnc(R3, R4, rm, Qmul, yQmul, &rs);
+ char buf[sizeof(G1) * 4 + sizeof(G2) * 4];
+ cybozu::MemoryOutputStream os(buf, sizeof(buf));
+ S1.save(os);
+ T1.save(os);
+ S2.save(os);
+ T2.save(os);
+ R1.save(os);
+ R2.save(os);
+ R3.save(os);
+ R4.save(os);
+ Fr& c = zkp.d_[0];
+ Fr& sp = zkp.d_[1];
+ Fr& ss = zkp.d_[2];
+ Fr& sm = zkp.d_[3];
+ c.setHashOf(buf, os.getPos());
+ Fr::mul(sp, c, p);
+ sp += rp;
+ Fr::mul(ss, c, s);
+ ss += rs;
+ Fr::mul(sm, c, m);
+ sm += rm;
+ }
+ template<class G1, class G2, class I1, class I2, class MulG1, class MulG2>
+ static bool verifyZkpEq(const ZkpEq& zkp, const G1& S1, const G1& T1, const G2& S2, const G2& T2, const mcl::fp::WindowMethod<I1>& Pmul, const MulG1& xPmul, const mcl::fp::WindowMethod<I2>& Qmul, const MulG2& yQmul)
+ {
+ const Fr& c = zkp.d_[0];
+ const Fr& sp = zkp.d_[1];
+ const Fr& ss = zkp.d_[2];
+ const Fr& sm = zkp.d_[3];
+ G1 R1, R2, X1;
+ G2 R3, R4, X2;
+ ElGamalEnc(R1, R2, sm, Pmul, xPmul, &sp);
+ G1::mul(X1, S1, c);
+ R1 -= X1;
+ G1::mul(X1, T1, c);
+ R2 -= X1;
+ ElGamalEnc(R3, R4, sm, Qmul, yQmul, &ss);
+ G2::mul(X2, S2, c);
+ R3 -= X2;
+ G2::mul(X2, T2, c);
+ R4 -= X2;
+ char buf[sizeof(G1) * 4 + sizeof(G2) * 4];
+ cybozu::MemoryOutputStream os(buf, sizeof(buf));
+ S1.save(os);
+ T1.save(os);
+ S2.save(os);
+ T2.save(os);
+ R1.save(os);
+ R2.save(os);
+ R3.save(os);
+ R4.save(os);
+ Fr c2;
+ c2.setHashOf(buf, os.getPos());
+ return c == c2;
+ }
+ /*
+ encRand1, encRand2 are random values use for ElGamalEnc()
+ */
+ template<class G1, class G2, class I1, class I2, class MulG1, class MulG2>
+ static void makeZkpBinEq(ZkpBinEq& zkp, G1& S1, G1& T1, G2& S2, G2& T2, int m, const mcl::fp::WindowMethod<I1>& Pmul, const MulG1& xPmul, const mcl::fp::WindowMethod<I2>& Qmul, const MulG2& yQmul)
+ {
+ if (m != 0 && m != 1) throw cybozu::Exception("makeZkpBinEq:bad m") << m;
+ Fr *d = &zkp.d_[0];
+ Fr *spm = &zkp.d_[2];
+ Fr& ss = zkp.d_[4];
+ Fr& sp = zkp.d_[5];
+ Fr& sm = zkp.d_[6];
+ Fr p, s;
+ p.setRand();
+ s.setRand();
+ ElGamalEnc(S1, T1, m, Pmul, xPmul, &p);
+ ElGamalEnc(S2, T2, m, Qmul, yQmul, &s);
+ d[1-m].setRand();
+ spm[1-m].setRand();
+ G1 R1[2], R2[2], X1;
+ Pmul.mul(static_cast<I1&>(R1[1-m]), spm[1-m]);
+ G1::mul(X1, T1, d[1-m]);
+ R1[1-m] -= X1;
+ if (m == 0) {
+ G1::sub(X1, S1, P_);
+ G1::mul(X1, X1, d[1-m]);
+ } else {
+ G1::mul(X1, S1, d[1-m]);
+ }
+ xPmul.mul(R2[1-m], spm[1-m]);
+ R2[1-m] -= X1;
+ Fr rpm, rp, rs, rm;
+ rpm.setRand();
+ rp.setRand();
+ rs.setRand();
+ rm.setRand();
+ ElGamalEnc(R2[m], R1[m], 0, Pmul, xPmul, &rpm);
+ G1 R3, R4;
+ G2 R5, R6;
+ ElGamalEnc(R4, R3, rm, Pmul, xPmul, &rp);
+ ElGamalEnc(R6, R5, rm, Qmul, yQmul, &rs);
+ char buf[sizeof(Fr) * 12];
+ cybozu::MemoryOutputStream os(buf, sizeof(buf));
+ S1.save(os);
+ T1.save(os);
+ R1[0].save(os);
+ R1[1].save(os);
+ R2[0].save(os);
+ R2[1].save(os);
+ R3.save(os);
+ R4.save(os);
+ R5.save(os);
+ R6.save(os);
+ Fr c;
+ c.setHashOf(buf, os.getPos());
+ Fr::sub(d[m], c, d[1-m]);
+ Fr::mul(spm[m], d[m], p);
+ spm[m] += rpm;
+ Fr::mul(sp, c, p);
+ sp += rp;
+ Fr::mul(ss, c, s);
+ ss += rs;
+ Fr::mul(sm, c, m);
+ sm += rm;
+ }
+ template<class G1, class G2, class I1, class I2, class MulG1, class MulG2>
+ static bool verifyZkpBinEq(const ZkpBinEq& zkp, const G1& S1, const G1& T1, const G2& S2, const G2& T2, const mcl::fp::WindowMethod<I1>& Pmul, const MulG1& xPmul, const mcl::fp::WindowMethod<I2>& Qmul, const MulG2& yQmul)
+ {
+ const Fr *d = &zkp.d_[0];
+ const Fr *spm = &zkp.d_[2];
+ const Fr& ss = zkp.d_[4];
+ const Fr& sp = zkp.d_[5];
+ const Fr& sm = zkp.d_[6];
+ G1 R1[2], R2[2], X1;
+ for (int i = 0; i < 2; i++) {
+ Pmul.mul(static_cast<I1&>(R1[i]), spm[i]);
+ G1::mul(X1, T1, d[i]);
+ R1[i] -= X1;
+ }
+ xPmul.mul(R2[0], spm[0]);
+ G1::mul(X1, S1, d[0]);
+ R2[0] -= X1;
+ xPmul.mul(R2[1], spm[1]);
+ G1::sub(X1, S1, P_);
+ G1::mul(X1, X1, d[1]);
+ R2[1] -= X1;
+ Fr c;
+ Fr::add(c, d[0], d[1]);
+ G1 R3, R4;
+ G2 R5, R6;
+ ElGamalEnc(R4, R3, sm, Pmul, xPmul, &sp);
+ G1::mul(X1, T1, c);
+ R3 -= X1;
+ G1::mul(X1, S1, c);
+ R4 -= X1;
+ ElGamalEnc(R6, R5, sm, Qmul, yQmul, &ss);
+ G2 X2;
+ G2::mul(X2, T2, c);
+ R5 -= X2;
+ G2::mul(X2, S2, c);
+ R6 -= X2;
+ char buf[sizeof(Fr) * 12];
+ cybozu::MemoryOutputStream os(buf, sizeof(buf));
+ S1.save(os);
+ T1.save(os);
+ R1[0].save(os);
+ R1[1].save(os);
+ R2[0].save(os);
+ R2[1].save(os);
+ R3.save(os);
+ R4.save(os);
+ R5.save(os);
+ R6.save(os);
+ Fr c2;
+ c2.setHashOf(buf, os.getPos());
+ return c == c2;
+ }
+ /*
+ common method for PublicKey and PrecomputedPublicKey
+ */
+ template<class T>
+ struct PublicKeyMethod {
+ /*
+ you can use INT as int64_t and Fr,
+ but the return type of dec() is int64_t.
+ */
+ template<class INT>
+ void enc(CipherTextG1& c, const INT& m) const
+ {
+ static_cast<const T&>(*this).encG1(c, m);
+ }
+ template<class INT>
+ void enc(CipherTextG2& c, const INT& m) const
+ {
+ static_cast<const T&>(*this).encG2(c, m);
+ }
+ template<class INT>
+ void enc(CipherTextA& c, const INT& m) const
+ {
+ enc(c.c1_, m);
+ enc(c.c2_, m);
+ }
+ template<class INT>
+ void enc(CipherTextGT& c, const INT& m) const
+ {
+ static_cast<const T&>(*this).encGT(c, m);
+ }
+ template<class INT>
+ void enc(CipherText& c, const INT& m, bool multiplied = false) const
+ {
+ c.isMultiplied_ = multiplied;
+ if (multiplied) {
+ enc(c.m_, m);
+ } else {
+ enc(c.a_, m);
+ }
+ }
+ /*
+ reRand method is for circuit privacy
+ */
+ template<class CT>
+ void reRandT(CT& c) const
+ {
+ CT c0;
+ static_cast<const T&>(*this).enc(c0, 0);
+ CT::add(c, c, c0);
+ }
+ void reRand(CipherTextG1& c) const { reRandT(c); }
+ void reRand(CipherTextG2& c) const { reRandT(c); }
+ void reRand(CipherTextGT& c) const { reRandT(c); }
+ void reRand(CipherText& c) const
+ {
+ if (c.isMultiplied()) {
+ reRandT(c.m_);
+ } else {
+ reRandT(c.a_);
+ }
+ }
+ /*
+ convert from CipherTextG1 to CipherTextGT
+ */
+ void convert(CipherTextGT& cm, const CipherTextG1& c1) const
+ {
+ /*
+ Enc(1) = (S, T) = (Q + r yQ, rQ) = (Q, 0) if r = 0
+ cm = c1 * (Q, 0) = (S, T) * (Q, 0) = (e(S, Q), 1, e(T, Q), 1)
+ */
+ precomputedMillerLoop(cm.g_[0], c1.getS(), Qcoeff_);
+ finalExp(cm.g_[0], cm.g_[0]);
+ precomputedMillerLoop(cm.g_[2], c1.getT(), Qcoeff_);
+ finalExp(cm.g_[2], cm.g_[2]);
+
+ cm.g_[1] = cm.g_[3] = 1;
+ }
+ /*
+ convert from CipherTextG2 to CipherTextGT
+ */
+ void convert(CipherTextGT& cm, const CipherTextG2& c2) const
+ {
+ /*
+ Enc(1) = (S, T) = (P + r xP, rP) = (P, 0) if r = 0
+ cm = (P, 0) * c2 = (e(P, S), e(P, T), 1, 1)
+ */
+ pairing(cm.g_[0], P_, c2.getS());
+ pairing(cm.g_[1], P_, c2.getT());
+ cm.g_[2] = cm.g_[3] = 1;
+ }
+ void convert(CipherTextGT& cm, const CipherTextA& ca) const
+ {
+ convert(cm, ca.c1_);
+ }
+ void convert(CipherText& cm, const CipherText& ca) const
+ {
+ if (ca.isMultiplied()) throw cybozu::Exception("she:PublicKey:convertCipherText:already isMultiplied");
+ cm.isMultiplied_ = true;
+ convert(cm.m_, ca.a_);
+ }
+ };
+public:
+ class PublicKey : public fp::Serializable<PublicKey,
+ PublicKeyMethod<PublicKey> > {
+ G1 xP_;
+ G2 yQ_;
+ friend class SecretKey;
+ friend class PrecomputedPublicKey;
+ template<class T>
+ friend struct PublicKeyMethod;
+ template<class G>
+ struct MulG {
+ const G& base;
+ MulG(const G& base) : base(base) {}
+ template<class INT>
+ void mul(G& out, const INT& m) const
+ {
+ G::mul(out, base, m);
+ }
+ };
+ void set(const Fr& x, const Fr& y)
+ {
+ G1::mul(xP_, P_, x);
+ if (!isG1only_) G2::mul(yQ_, Q_, y);
+ }
+ template<class INT>
+ void encG1(CipherTextG1& c, const INT& m) const
+ {
+ const MulG<G1> xPmul(xP_);
+ ElGamalEnc(c.S_, c.T_, m, PhashTbl_.getWM(), xPmul);
+ }
+ template<class INT>
+ void encG2(CipherTextG2& c, const INT& m) const
+ {
+ const MulG<G2> yQmul(yQ_);
+ ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQmul);
+ }
+public:
+ void encWithZkpBin(CipherTextG1& c, ZkpBin& zkp, int m) const
+ {
+ Fr encRand;
+ encRand.setRand();
+ const MulG<G1> xPmul(xP_);
+ ElGamalEnc(c.S_, c.T_, m, PhashTbl_.getWM(), xPmul, &encRand);
+ makeZkpBin(zkp, c.S_, c.T_, encRand, P_, m, PhashTbl_.getWM(), xPmul);
+ }
+ void encWithZkpBin(CipherTextG2& c, ZkpBin& zkp, int m) const
+ {
+ Fr encRand;
+ encRand.setRand();
+ const MulG<G2> yQmul(yQ_);
+ ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQmul, &encRand);
+ makeZkpBin(zkp, c.S_, c.T_, encRand, Q_, m, QhashTbl_.getWM(), yQmul);
+ }
+ bool verify(const CipherTextG1& c, const ZkpBin& zkp) const
+ {
+ const MulG<G1> xPmul(xP_);
+ return verifyZkpBin(c.S_, c.T_, P_, zkp, PhashTbl_.getWM(), xPmul);
+ }
+ bool verify(const CipherTextG2& c, const ZkpBin& zkp) const
+ {
+ const MulG<G2> yQmul(yQ_);
+ return verifyZkpBin(c.S_, c.T_, Q_, zkp, QhashTbl_.getWM(), yQmul);
+ }
+ template<class INT>
+ void encWithZkpEq(CipherTextG1& c1, CipherTextG2& c2, ZkpEq& zkp, const INT& m) const
+ {
+ const MulG<G1> xPmul(xP_);
+ const MulG<G2> yQmul(yQ_);
+ makeZkpEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, m, PhashTbl_.getWM(), xPmul, QhashTbl_.getWM(), yQmul);
+ }
+ bool verify(const CipherTextG1& c1, const CipherTextG2& c2, const ZkpEq& zkp) const
+ {
+ const MulG<G1> xPmul(xP_);
+ const MulG<G2> yQmul(yQ_);
+ return verifyZkpEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, PhashTbl_.getWM(), xPmul, QhashTbl_.getWM(), yQmul);
+ }
+ void encWithZkpBinEq(CipherTextG1& c1, CipherTextG2& c2, ZkpBinEq& zkp, int m) const
+ {
+ const MulG<G1> xPmul(xP_);
+ const MulG<G2> yQmul(yQ_);
+ makeZkpBinEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, m, PhashTbl_.getWM(), xPmul, QhashTbl_.getWM(), yQmul);
+ }
+ bool verify(const CipherTextG1& c1, const CipherTextG2& c2, const ZkpBinEq& zkp) const
+ {
+ const MulG<G1> xPmul(xP_);
+ const MulG<G2> yQmul(yQ_);
+ return verifyZkpBinEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, PhashTbl_.getWM(), xPmul, QhashTbl_.getWM(), yQmul);
+ }
+ template<class INT>
+ void encGT(CipherTextGT& c, const INT& m) const
+ {
+ /*
+ (s, t, u, v) = ((e^x)^a (e^y)^b (e^-xy)^c e^m, e^b, e^a, e^c)
+ s = e(a xP + m P, Q)e(b P - c xP, yQ)
+ */
+ Fr ra, rb, rc;
+ ra.setRand();
+ rb.setRand();
+ rc.setRand();
+ GT e;
+
+ G1 P1, P2;
+ G1::mul(P1, xP_, ra);
+ if (m) {
+// G1::mul(P2, P, m);
+ PhashTbl_.mulByWindowMethod(P2, m);
+ P1 += P2;
+ }
+// millerLoop(c.g[0], P1, Q);
+ precomputedMillerLoop(c.g_[0], P1, Qcoeff_);
+// G1::mul(P1, P, rb);
+ PhashTbl_.mulByWindowMethod(P1, rb);
+ G1::mul(P2, xP_, rc);
+ P1 -= P2;
+ millerLoop(e, P1, yQ_);
+ c.g_[0] *= e;
+ finalExp(c.g_[0], c.g_[0]);
+#if 1
+ ePQhashTbl_.mulByWindowMethod(c.g_[1], rb);
+ ePQhashTbl_.mulByWindowMethod(c.g_[2], ra);
+ ePQhashTbl_.mulByWindowMethod(c.g_[3], rc);
+#else
+ GT::pow(c.g_[1], ePQ_, rb);
+ GT::pow(c.g_[2], ePQ_, ra);
+ GT::pow(c.g_[3], ePQ_, rc);
+#endif
+ }
+ public:
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
+ {
+ xP_.load(pb, is, ioMode); if (!*pb) return;
+ if (!isG1only_) yQ_.load(pb, is, ioMode);
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ xP_.save(pb, os, ioMode); if (!*pb) return;
+ if (isG1only_) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ yQ_.save(pb, os, ioMode);
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("she:PublicKey:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("she:PublicKey:save");
+ }
+ friend std::istream& operator>>(std::istream& is, PublicKey& self)
+ {
+ self.load(is, fp::detectIoMode(G1::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const PublicKey& self)
+ {
+ self.save(os, fp::detectIoMode(G1::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const PublicKey& rhs) const
+ {
+ return xP_ == rhs.xP_ && (isG1only_ || yQ_ == rhs.yQ_);
+ }
+ bool operator!=(const PublicKey& rhs) const { return !operator==(rhs); }
+ };
+
+ class PrecomputedPublicKey : public fp::Serializable<PrecomputedPublicKey,
+ PublicKeyMethod<PrecomputedPublicKey> > {
+ typedef local::InterfaceForHashTable<GT, false> GTasEC;
+ typedef mcl::fp::WindowMethod<GTasEC> GTwin;
+ template<class T>
+ friend struct PublicKeyMethod;
+ GT exPQ_;
+ GT eyPQ_;
+ GT exyPQ_;
+ GTwin exPQwm_;
+ GTwin eyPQwm_;
+ GTwin exyPQwm_;
+ mcl::fp::WindowMethod<G1> xPwm_;
+ mcl::fp::WindowMethod<G2> yQwm_;
+ template<class T>
+ void mulByWindowMethod(GT& x, const GTwin& wm, const T& y) const
+ {
+ wm.mul(static_cast<GTasEC&>(x), y);
+ }
+ template<class INT>
+ void encG1(CipherTextG1& c, const INT& m) const
+ {
+ ElGamalEnc(c.S_, c.T_, m, PhashTbl_.getWM(), xPwm_);
+ }
+ template<class INT>
+ void encG2(CipherTextG2& c, const INT& m) const
+ {
+ ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQwm_);
+ }
+ template<class INT>
+ void encGT(CipherTextGT& c, const INT& m) const
+ {
+ /*
+ (s, t, u, v) = (e^m e^(xya), (e^x)^b, (e^y)^c, e^(b + c - a))
+ */
+ Fr ra, rb, rc;
+ ra.setRand();
+ rb.setRand();
+ rc.setRand();
+ GT t;
+ ePQhashTbl_.mulByWindowMethod(c.g_[0], m); // e^m
+ mulByWindowMethod(t, exyPQwm_, ra); // (e^xy)^a
+ c.g_[0] *= t;
+ mulByWindowMethod(c.g_[1], exPQwm_, rb); // (e^x)^b
+ mulByWindowMethod(c.g_[2], eyPQwm_, rc); // (e^y)^c
+ rb += rc;
+ rb -= ra;
+ ePQhashTbl_.mulByWindowMethod(c.g_[3], rb);
+ }
+ public:
+ void init(const PublicKey& pub)
+ {
+ const size_t bitSize = Fr::getBitSize();
+ xPwm_.init(pub.xP_, bitSize, local::winSize);
+ if (isG1only_) return;
+ yQwm_.init(pub.yQ_, bitSize, local::winSize);
+ pairing(exPQ_, pub.xP_, Q_);
+ pairing(eyPQ_, P_, pub.yQ_);
+ pairing(exyPQ_, pub.xP_, pub.yQ_);
+ exPQwm_.init(static_cast<const GTasEC&>(exPQ_), bitSize, local::winSize);
+ eyPQwm_.init(static_cast<const GTasEC&>(eyPQ_), bitSize, local::winSize);
+ exyPQwm_.init(static_cast<const GTasEC&>(exyPQ_), bitSize, local::winSize);
+ }
+ void encWithZkpBin(CipherTextG1& c, ZkpBin& zkp, int m) const
+ {
+ Fr encRand;
+ encRand.setRand();
+ ElGamalEnc(c.S_, c.T_, m, PhashTbl_.getWM(), xPwm_, &encRand);
+ makeZkpBin(zkp, c.S_, c.T_, encRand, P_, m, PhashTbl_.getWM(), xPwm_);
+ }
+ void encWithZkpBin(CipherTextG2& c, ZkpBin& zkp, int m) const
+ {
+ Fr encRand;
+ encRand.setRand();
+ ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQwm_, &encRand);
+ makeZkpBin(zkp, c.S_, c.T_, encRand, Q_, m, QhashTbl_.getWM(), yQwm_);
+ }
+ bool verify(const CipherTextG1& c, const ZkpBin& zkp) const
+ {
+ return verifyZkpBin(c.S_, c.T_, P_, zkp, PhashTbl_.getWM(), xPwm_);
+ }
+ bool verify(const CipherTextG2& c, const ZkpBin& zkp) const
+ {
+ return verifyZkpBin(c.S_, c.T_, Q_, zkp, QhashTbl_.getWM(), yQwm_);
+ }
+ template<class INT>
+ void encWithZkpEq(CipherTextG1& c1, CipherTextG2& c2, ZkpEq& zkp, const INT& m) const
+ {
+ makeZkpEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, m, PhashTbl_.getWM(), xPwm_, QhashTbl_.getWM(), yQwm_);
+ }
+ bool verify(const CipherTextG1& c1, const CipherTextG2& c2, const ZkpEq& zkp) const
+ {
+ return verifyZkpEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, PhashTbl_.getWM(), xPwm_, QhashTbl_.getWM(), yQwm_);
+ }
+ void encWithZkpBinEq(CipherTextG1& c1, CipherTextG2& c2, ZkpBinEq& zkp, int m) const
+ {
+ makeZkpBinEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, m, PhashTbl_.getWM(), xPwm_, QhashTbl_.getWM(), yQwm_);
+ }
+ bool verify(const CipherTextG1& c1, const CipherTextG2& c2, const ZkpBinEq& zkp) const
+ {
+ return verifyZkpBinEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, PhashTbl_.getWM(), xPwm_, QhashTbl_.getWM(), yQwm_);
+ }
+ };
+ class CipherTextA {
+ CipherTextG1 c1_;
+ CipherTextG2 c2_;
+ friend class SecretKey;
+ friend class PublicKey;
+ friend class CipherTextGT;
+ template<class T>
+ friend struct PublicKeyMethod;
+ public:
+ void clear()
+ {
+ c1_.clear();
+ c2_.clear();
+ }
+ static void add(CipherTextA& z, const CipherTextA& x, const CipherTextA& y)
+ {
+ CipherTextG1::add(z.c1_, x.c1_, y.c1_);
+ CipherTextG2::add(z.c2_, x.c2_, y.c2_);
+ }
+ static void sub(CipherTextA& z, const CipherTextA& x, const CipherTextA& y)
+ {
+ CipherTextG1::sub(z.c1_, x.c1_, y.c1_);
+ CipherTextG2::sub(z.c2_, x.c2_, y.c2_);
+ }
+ static void mul(CipherTextA& z, const CipherTextA& x, int64_t y)
+ {
+ CipherTextG1::mul(z.c1_, x.c1_, y);
+ CipherTextG2::mul(z.c2_, x.c2_, y);
+ }
+ static void neg(CipherTextA& y, const CipherTextA& x)
+ {
+ CipherTextG1::neg(y.c1_, x.c1_);
+ CipherTextG2::neg(y.c2_, x.c2_);
+ }
+ void add(const CipherTextA& c) { add(*this, *this, c); }
+ void sub(const CipherTextA& c) { sub(*this, *this, c); }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
+ {
+ c1_.load(pb, is, ioMode); if (!*pb) return;
+ c2_.load(pb, is, ioMode);
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ c1_.save(pb, os, ioMode); if (!*pb) return;
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ c2_.save(pb, os, ioMode);
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("she:CipherTextA:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("she:CipherTextA:save");
+ }
+ friend std::istream& operator>>(std::istream& is, CipherTextA& self)
+ {
+ self.load(is, fp::detectIoMode(G1::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const CipherTextA& self)
+ {
+ self.save(os, fp::detectIoMode(G1::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const CipherTextA& rhs) const
+ {
+ return c1_ == rhs.c1_ && c2_ == rhs.c2_;
+ }
+ bool operator!=(const CipherTextA& rhs) const { return !operator==(rhs); }
+ };
+
+ class CipherTextGT : public fp::Serializable<CipherTextGT> {
+ GT g_[4];
+ friend class SecretKey;
+ friend class PublicKey;
+ friend class PrecomputedPublicKey;
+ friend class CipherTextA;
+ template<class T>
+ friend struct PublicKeyMethod;
+ public:
+ void clear()
+ {
+ for (int i = 0; i < 4; i++) {
+ g_[i].setOne();
+ }
+ }
+ static void neg(CipherTextGT& y, const CipherTextGT& x)
+ {
+ for (int i = 0; i < 4; i++) {
+ GT::unitaryInv(y.g_[i], x.g_[i]);
+ }
+ }
+ static void add(CipherTextGT& z, const CipherTextGT& x, const CipherTextGT& y)
+ {
+ /*
+ (g[i]) + (g'[i]) = (g[i] * g'[i])
+ */
+ for (int i = 0; i < 4; i++) {
+ GT::mul(z.g_[i], x.g_[i], y.g_[i]);
+ }
+ }
+ static void sub(CipherTextGT& z, const CipherTextGT& x, const CipherTextGT& y)
+ {
+ /*
+ (g[i]) - (g'[i]) = (g[i] / g'[i])
+ */
+ GT t;
+ for (size_t i = 0; i < 4; i++) {
+ GT::unitaryInv(t, y.g_[i]);
+ GT::mul(z.g_[i], x.g_[i], t);
+ }
+ }
+ static void mulML(CipherTextGT& z, const CipherTextG1& x, const CipherTextG2& y)
+ {
+ /*
+ (S1, T1) * (S2, T2) = (ML(S1, S2), ML(S1, T2), ML(T1, S2), ML(T1, T2))
+ */
+ tensorProductML(z.g_, x.S_, x.T_, y.S_, y.T_);
+ }
+ static void finalExp(CipherTextGT& y, const CipherTextGT& x)
+ {
+ finalExp4(y.g_, x.g_);
+ }
+ /*
+ mul(x, y) = mulML(x, y) + finalExp
+ mul(c11, c12) + mul(c21, c22)
+ = finalExp(mulML(c11, c12) + mulML(c21, c22)),
+ then one finalExp can be reduced
+ */
+ static void mul(CipherTextGT& z, const CipherTextG1& x, const CipherTextG2& y)
+ {
+ /*
+ (S1, T1) * (S2, T2) = (e(S1, S2), e(S1, T2), e(T1, S2), e(T1, T2))
+ */
+ mulML(z, x, y);
+ finalExp(z, z);
+ }
+ static void mul(CipherTextGT& z, const CipherTextA& x, const CipherTextA& y)
+ {
+ mul(z, x.c1_, y.c2_);
+ }
+ static void mul(CipherTextGT& z, const CipherTextGT& x, int64_t y)
+ {
+ for (int i = 0; i < 4; i++) {
+ GT::pow(z.g_[i], x.g_[i], y);
+ }
+ }
+ void add(const CipherTextGT& c) { add(*this, *this, c); }
+ void sub(const CipherTextGT& c) { sub(*this, *this, c); }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
+ {
+ for (int i = 0; i < 4; i++) {
+ g_[i].load(pb, is, ioMode); if (!*pb) return;
+ }
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
+ {
+ const char sep = *fp::getIoSeparator(ioMode);
+ g_[0].save(pb, os, ioMode); if (!*pb) return;
+ for (int i = 1; i < 4; i++) {
+ if (sep) {
+ cybozu::writeChar(pb, os, sep);
+ if (!*pb) return;
+ }
+ g_[i].save(pb, os, ioMode); if (!*pb) return;
+ }
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("she:CipherTextGT:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("she:CipherTextGT:save");
+ }
+ friend std::istream& operator>>(std::istream& is, CipherTextGT& self)
+ {
+ self.load(is, fp::detectIoMode(G1::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const CipherTextGT& self)
+ {
+ self.save(os, fp::detectIoMode(G1::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const CipherTextGT& rhs) const
+ {
+ for (int i = 0; i < 4; i++) {
+ if (g_[i] != rhs.g_[i]) return false;
+ }
+ return true;
+ }
+ bool operator!=(const CipherTextGT& rhs) const { return !operator==(rhs); }
+ };
+
+ class CipherText : public fp::Serializable<CipherText> {
+ bool isMultiplied_;
+ CipherTextA a_;
+ CipherTextGT m_;
+ friend class SecretKey;
+ friend class PublicKey;
+ template<class T>
+ friend struct PublicKeyMethod;
+ public:
+ CipherText() : isMultiplied_(false) {}
+ void clearAsAdded()
+ {
+ isMultiplied_ = false;
+ a_.clear();
+ }
+ void clearAsMultiplied()
+ {
+ isMultiplied_ = true;
+ m_.clear();
+ }
+ bool isMultiplied() const { return isMultiplied_; }
+ static void add(CipherText& z, const CipherText& x, const CipherText& y)
+ {
+ if (x.isMultiplied() && y.isMultiplied()) {
+ z.isMultiplied_ = true;
+ CipherTextGT::add(z.m_, x.m_, y.m_);
+ return;
+ }
+ if (!x.isMultiplied() && !y.isMultiplied()) {
+ z.isMultiplied_ = false;
+ CipherTextA::add(z.a_, x.a_, y.a_);
+ return;
+ }
+ throw cybozu::Exception("she:CipherText:add:mixed CipherText");
+ }
+ static void sub(CipherText& z, const CipherText& x, const CipherText& y)
+ {
+ if (x.isMultiplied() && y.isMultiplied()) {
+ z.isMultiplied_ = true;
+ CipherTextGT::sub(z.m_, x.m_, y.m_);
+ return;
+ }
+ if (!x.isMultiplied() && !y.isMultiplied()) {
+ z.isMultiplied_ = false;
+ CipherTextA::sub(z.a_, x.a_, y.a_);
+ return;
+ }
+ throw cybozu::Exception("she:CipherText:sub:mixed CipherText");
+ }
+ static void neg(CipherText& y, const CipherText& x)
+ {
+ if (x.isMultiplied()) {
+ y.isMultiplied_ = true;
+ CipherTextGT::neg(y.m_, x.m_);
+ return;
+ } else {
+ y.isMultiplied_ = false;
+ CipherTextA::neg(y.a_, x.a_);
+ return;
+ }
+ }
+ static void mul(CipherText& z, const CipherText& x, const CipherText& y)
+ {
+ if (x.isMultiplied() || y.isMultiplied()) {
+ throw cybozu::Exception("she:CipherText:mul:mixed CipherText");
+ }
+ z.isMultiplied_ = true;
+ CipherTextGT::mul(z.m_, x.a_, y.a_);
+ }
+ static void mul(CipherText& z, const CipherText& x, int64_t y)
+ {
+ if (x.isMultiplied()) {
+ CipherTextGT::mul(z.m_, x.m_, y);
+ } else {
+ CipherTextA::mul(z.a_, x.a_, y);
+ }
+ }
+ void add(const CipherText& c) { add(*this, *this, c); }
+ void sub(const CipherText& c) { sub(*this, *this, c); }
+ void mul(const CipherText& c) { mul(*this, *this, c); }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
+ {
+ cybozu::writeChar(pb, isMultiplied_ ? '0' : '1', is); if (!*pb) return;
+ if (isMultiplied()) {
+ m_.load(pb, is, ioMode);
+ } else {
+ a_.load(pb, is, ioMode);
+ }
+ }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
+ {
+ char c;
+ if (!cybozu::readChar(&c, os)) return;
+ if (c == '0' || c == '1') {
+ isMultiplied_ = c == '0';
+ } else {
+ *pb = false;
+ return;
+ }
+ if (isMultiplied()) {
+ m_.save(pb, os, ioMode);
+ } else {
+ a_.save(pb, os, ioMode);
+ }
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = IoSerialize)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("she:CipherText:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int ioMode = IoSerialize) const
+ {
+ bool b;
+ save(&b, os, ioMode);
+ if (!b) throw cybozu::Exception("she:CipherText:save");
+ }
+ friend std::istream& operator>>(std::istream& is, CipherText& self)
+ {
+ self.load(is, fp::detectIoMode(G1::getIoMode(), is));
+ return is;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const CipherText& self)
+ {
+ self.save(os, fp::detectIoMode(G1::getIoMode(), os));
+ return os;
+ }
+ bool operator==(const CipherTextGT& rhs) const
+ {
+ if (isMultiplied() != rhs.isMultiplied()) return false;
+ if (isMultiplied()) {
+ return m_ == rhs.m_;
+ }
+ return a_ == rhs.a_;
+ }
+ bool operator!=(const CipherTextGT& rhs) const { return !operator==(rhs); }
+ };
+};
+typedef local::HashTable<G1> HashTableG1;
+typedef local::HashTable<G2> HashTableG2;
+typedef local::HashTable<Fp12, false> HashTableGT;
+
+template<size_t dummyInpl> G1 SHET<dummyInpl>::P_;
+template<size_t dummyInpl> G2 SHET<dummyInpl>::Q_;
+template<size_t dummyInpl> Fp12 SHET<dummyInpl>::ePQ_;
+template<size_t dummyInpl> std::vector<Fp6> SHET<dummyInpl>::Qcoeff_;
+template<size_t dummyInpl> HashTableG1 SHET<dummyInpl>::PhashTbl_;
+template<size_t dummyInpl> HashTableG2 SHET<dummyInpl>::QhashTbl_;
+template<size_t dummyInpl> HashTableGT SHET<dummyInpl>::ePQhashTbl_;
+template<size_t dummyInpl> bool SHET<dummyInpl>::useDecG1ViaGT_;
+template<size_t dummyInpl> bool SHET<dummyInpl>::useDecG2ViaGT_;
+template<size_t dummyInpl> bool SHET<dummyInpl>::isG1only_;
+typedef mcl::she::SHET<> SHE;
+typedef SHE::SecretKey SecretKey;
+typedef SHE::PublicKey PublicKey;
+typedef SHE::PrecomputedPublicKey PrecomputedPublicKey;
+typedef SHE::CipherTextG1 CipherTextG1;
+typedef SHE::CipherTextG2 CipherTextG2;
+typedef SHE::CipherTextGT CipherTextGT;
+typedef SHE::CipherTextA CipherTextA;
+typedef CipherTextGT CipherTextGM; // old class
+typedef SHE::CipherText CipherText;
+typedef SHE::ZkpBin ZkpBin;
+typedef SHE::ZkpEq ZkpEq;
+typedef SHE::ZkpBinEq ZkpBinEq;
+
+inline void init(const mcl::CurveParam& cp = mcl::BN254, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum)
+{
+ SHE::init(cp, hashSize, tryNum);
+}
+inline void initG1only(const mcl::EcParam& para, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum)
+{
+ SHE::initG1only(para, hashSize, tryNum);
+}
+inline void init(size_t hashSize, size_t tryNum = local::defaultTryNum) { SHE::init(hashSize, tryNum); }
+inline void setRangeForG1DLP(size_t hashSize) { SHE::setRangeForG1DLP(hashSize); }
+inline void setRangeForG2DLP(size_t hashSize) { SHE::setRangeForG2DLP(hashSize); }
+inline void setRangeForGTDLP(size_t hashSize) { SHE::setRangeForGTDLP(hashSize); }
+inline void setRangeForDLP(size_t hashSize) { SHE::setRangeForDLP(hashSize); }
+inline void setTryNum(size_t tryNum) { SHE::setTryNum(tryNum); }
+inline void useDecG1ViaGT(bool use = true) { SHE::useDecG1ViaGT(use); }
+inline void useDecG2ViaGT(bool use = true) { SHE::useDecG2ViaGT(use); }
+inline HashTableG1& getHashTableG1() { return SHE::PhashTbl_; }
+inline HashTableG2& getHashTableG2() { return SHE::QhashTbl_; }
+inline HashTableGT& getHashTableGT() { return SHE::ePQhashTbl_; }
+
+inline void add(CipherTextG1& z, const CipherTextG1& x, const CipherTextG1& y) { CipherTextG1::add(z, x, y); }
+inline void add(CipherTextG2& z, const CipherTextG2& x, const CipherTextG2& y) { CipherTextG2::add(z, x, y); }
+inline void add(CipherTextGT& z, const CipherTextGT& x, const CipherTextGT& y) { CipherTextGT::add(z, x, y); }
+inline void add(CipherText& z, const CipherText& x, const CipherText& y) { CipherText::add(z, x, y); }
+
+inline void sub(CipherTextG1& z, const CipherTextG1& x, const CipherTextG1& y) { CipherTextG1::sub(z, x, y); }
+inline void sub(CipherTextG2& z, const CipherTextG2& x, const CipherTextG2& y) { CipherTextG2::sub(z, x, y); }
+inline void sub(CipherTextGT& z, const CipherTextGT& x, const CipherTextGT& y) { CipherTextGT::sub(z, x, y); }
+inline void sub(CipherText& z, const CipherText& x, const CipherText& y) { CipherText::sub(z, x, y); }
+
+inline void neg(CipherTextG1& y, const CipherTextG1& x) { CipherTextG1::neg(y, x); }
+inline void neg(CipherTextG2& y, const CipherTextG2& x) { CipherTextG2::neg(y, x); }
+inline void neg(CipherTextGT& y, const CipherTextGT& x) { CipherTextGT::neg(y, x); }
+inline void neg(CipherText& y, const CipherText& x) { CipherText::neg(y, x); }
+
+template<class INT>
+inline void mul(CipherTextG1& z, const CipherTextG1& x, const INT& y) { CipherTextG1::mul(z, x, y); }
+template<class INT>
+inline void mul(CipherTextG2& z, const CipherTextG2& x, const INT& y) { CipherTextG2::mul(z, x, y); }
+template<class INT>
+inline void mul(CipherTextGT& z, const CipherTextGT& x, const INT& y) { CipherTextGT::mul(z, x, y); }
+template<class INT>
+inline void mul(CipherText& z, const CipherText& x, const INT& y) { CipherText::mul(z, x, y); }
+
+inline void mul(CipherTextGT& z, const CipherTextG1& x, const CipherTextG2& y) { CipherTextGT::mul(z, x, y); }
+inline void mul(CipherText& z, const CipherText& x, const CipherText& y) { CipherText::mul(z, x, y); }
+
+} } // mcl::she
+
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/util.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/util.hpp
new file mode 100644
index 000000000..edef971cb
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/util.hpp
@@ -0,0 +1,285 @@
+#pragma once
+/**
+ @file
+ @brief functions for T[]
+ @author MITSUNARI Shigeo(@herumi)
+ @license modified new BSD license
+ http://opensource.org/licenses/BSD-3-Clause
+*/
+#include <cybozu/bit_operation.hpp>
+
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable : 4456)
+ #pragma warning(disable : 4459)
+#endif
+
+namespace mcl { namespace fp {
+
+template<class T>
+T abs_(T x) { return x < 0 ? -x : x; }
+
+template<class T>
+T min_(T x, T y) { return x < y ? x : y; }
+
+template<class T>
+T max_(T x, T y) { return x < y ? y : x; }
+
+template<class T>
+void swap_(T& x, T& y)
+{
+ T t;
+ t = x;
+ x = y;
+ y = t;
+}
+
+
+/*
+ get pp such that p * pp = -1 mod M,
+ where p is prime and M = 1 << 64(or 32).
+ @param pLow [in] p mod M
+*/
+template<class T>
+T getMontgomeryCoeff(T pLow)
+{
+ T ret = 0;
+ T t = 0;
+ T x = 1;
+ for (size_t i = 0; i < sizeof(T) * 8; i++) {
+ if ((t & 1) == 0) {
+ t += pLow;
+ ret += x;
+ }
+ t >>= 1;
+ x <<= 1;
+ }
+ return ret;
+}
+
+template<class T>
+int compareArray(const T* x, const T* y, size_t n)
+{
+ for (size_t i = n - 1; i != size_t(-1); i--) {
+ T a = x[i];
+ T b = y[i];
+ if (a != b) return a < b ? -1 : 1;
+ }
+ return 0;
+}
+
+template<class T>
+bool isLessArray(const T *x, const T* y, size_t n)
+{
+ for (size_t i = n - 1; i != size_t(-1); i--) {
+ T a = x[i];
+ T b = y[i];
+ if (a != b) return a < b;
+ }
+ return false;
+}
+
+template<class T>
+bool isGreaterOrEqualArray(const T *x, const T* y, size_t n)
+{
+ return !isLessArray(x, y, n);
+}
+
+template<class T>
+bool isLessOrEqualArray(const T *x, const T* y, size_t n)
+{
+ for (size_t i = n - 1; i != size_t(-1); i--) {
+ T a = x[i];
+ T b = y[i];
+ if (a != b) return a < b;
+ }
+ return true;
+}
+
+template<class T>
+bool isGreaterArray(const T *x, const T* y, size_t n)
+{
+ return !isLessOrEqualArray(x, y, n);
+}
+
+template<class T>
+bool isEqualArray(const T* x, const T* y, size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ if (x[i] != y[i]) return false;
+ }
+ return true;
+}
+
+template<class T>
+bool isZeroArray(const T *x, size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ if (x[i]) return false;
+ }
+ return true;
+}
+
+template<class T>
+void clearArray(T *x, size_t begin, size_t end)
+{
+ for (size_t i = begin; i < end; i++) x[i] = 0;
+}
+
+template<class T>
+void copyArray(T *y, const T *x, size_t n)
+{
+ for (size_t i = 0; i < n; i++) y[i] = x[i];
+}
+
+/*
+ x &= (1 << bitSize) - 1
+*/
+template<class T>
+void maskArray(T *x, size_t n, size_t bitSize)
+{
+ const size_t TbitSize = sizeof(T) * 8;
+ assert(bitSize <= TbitSize * n);
+ const size_t q = bitSize / TbitSize;
+ const size_t r = bitSize % TbitSize;
+ if (r) {
+ x[q] &= (T(1) << r) - 1;
+ clearArray(x, q + 1, n);
+ } else {
+ clearArray(x, q, n);
+ }
+}
+
+/*
+ return non zero size of x[]
+ return 1 if x[] == 0
+*/
+template<class T>
+size_t getNonZeroArraySize(const T *x, size_t n)
+{
+ assert(n > 0);
+ while (n > 0) {
+ if (x[n - 1]) return n;
+ n--;
+ }
+ return 1;
+}
+
+/*
+ @param out [inout] : set element of G ; out = x^y[]
+ @param x [in]
+ @param y [in]
+ @param n [in] size of y[]
+ @param limitBit [in] const time version if the value is positive
+ @note &out != x and out = the unit element of G
+*/
+template<class G, class Mul, class Sqr, class T>
+void powGeneric(G& out, const G& x, const T *y, size_t n, const Mul& mul, const Sqr& sqr, void normalize(G&, const G&), size_t limitBit = 0)
+{
+ assert(&out != &x);
+ G tbl[4]; // tbl = { discard, x, x^2, x^3 }
+ T v;
+ bool constTime = limitBit > 0;
+ int maxBit = 0;
+ int m = 0;
+ while (n > 0) {
+ if (y[n - 1]) break;
+ n--;
+ }
+ if (n == 0) {
+ if (constTime) goto DummyLoop;
+ return;
+ }
+ if (!constTime && n == 1) {
+ switch (y[0]) {
+ case 1:
+ out = x;
+ return;
+ case 2:
+ sqr(out, x);
+ return;
+ case 3:
+ sqr(out, x);
+ mul(out, out, x);
+ return;
+ case 4:
+ sqr(out, x);
+ sqr(out, out);
+ return;
+ }
+ }
+ if (normalize != 0) {
+ normalize(tbl[0], x);
+ } else {
+ tbl[0] = x;
+ }
+ tbl[1] = tbl[0];
+ sqr(tbl[2], tbl[1]);
+ if (normalize != 0) { normalize(tbl[2], tbl[2]); }
+ mul(tbl[3], tbl[2], x);
+ if (normalize != 0) { normalize(tbl[3], tbl[3]); }
+ v = y[n - 1];
+ assert(v);
+ m = cybozu::bsr<T>(v);
+ maxBit = int(m + (n - 1) * sizeof(T) * 8);
+ if (m & 1) {
+ m--;
+ T idx = (v >> m) & 3;
+ assert(idx > 0);
+ out = tbl[idx];
+ } else {
+ out = x;
+ }
+ for (int i = (int)n - 1; i >= 0; i--) {
+ T v = y[i];
+ for (int j = m - 2; j >= 0; j -= 2) {
+ sqr(out, out);
+ sqr(out, out);
+ T idx = (v >> j) & 3;
+ if (idx == 0) {
+ if (constTime) mul(tbl[0], tbl[0], tbl[1]);
+ } else {
+ mul(out, out, tbl[idx]);
+ }
+ }
+ m = (int)sizeof(T) * 8;
+ }
+DummyLoop:
+ if (!constTime) return;
+ G D = out;
+ for (size_t i = maxBit + 1; i < limitBit; i += 2) {
+ sqr(D, D);
+ sqr(D, D);
+ mul(D, D, tbl[1]);
+ }
+}
+
+/*
+ shortcut of multiplication by Unit
+*/
+template<class T, class U>
+bool mulSmallUnit(T& z, const T& x, U y)
+{
+ switch (y) {
+ case 0: z.clear(); break;
+ case 1: z = x; break;
+ case 2: T::add(z, x, x); break;
+ case 3: { T t; T::add(t, x, x); T::add(z, t, x); break; }
+ case 4: T::add(z, x, x); T::add(z, z, z); break;
+ case 5: { T t; T::add(t, x, x); T::add(t, t, t); T::add(z, t, x); break; }
+ case 6: { T t; T::add(t, x, x); T::add(t, t, x); T::add(z, t, t); break; }
+ case 7: { T t; T::add(t, x, x); T::add(t, t, t); T::add(t, t, t); T::sub(z, t, x); break; }
+ case 8: T::add(z, x, x); T::add(z, z, z); T::add(z, z, z); break;
+ case 9: { T t; T::add(t, x, x); T::add(t, t, t); T::add(t, t, t); T::add(z, t, x); break; }
+ case 10: { T t; T::add(t, x, x); T::add(t, t, t); T::add(t, t, x); T::add(z, t, t); break; }
+ default:
+ return false;
+ }
+ return true;
+}
+
+} } // mcl::fp
+
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/vint.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/vint.hpp
new file mode 100644
index 000000000..b087688c3
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/vint.hpp
@@ -0,0 +1,1987 @@
+#pragma once
+/**
+ emulate mpz_class
+*/
+#include <cybozu/exception.hpp>
+#include <cybozu/bit_operation.hpp>
+#include <cybozu/xorshift.hpp>
+#include <assert.h>
+#ifndef CYBOZU_DONT_USE_STRING
+#include <iostream>
+#endif
+#include <mcl/array.hpp>
+#include <mcl/util.hpp>
+#include <mcl/randgen.hpp>
+#include <mcl/conversion.hpp>
+
+#if defined(__EMSCRIPTEN__) || defined(__wasm__)
+ #define MCL_VINT_64BIT_PORTABLE
+ #define MCL_VINT_FIXED_BUFFER
+#endif
+#ifndef MCL_MAX_BIT_SIZE
+ #define MCL_MAX_BIT_SIZE 384
+#endif
+
+#ifndef MCL_SIZEOF_UNIT
+ #if defined(CYBOZU_OS_BIT) && (CYBOZU_OS_BIT == 32)
+ #define MCL_SIZEOF_UNIT 4
+ #else
+ #define MCL_SIZEOF_UNIT 8
+ #endif
+#endif
+
+namespace mcl {
+
+namespace vint {
+
+#if MCL_SIZEOF_UNIT == 8
+typedef uint64_t Unit;
+#else
+typedef uint32_t Unit;
+#endif
+
+template<class T>
+void dump(const T *x, size_t n, const char *msg = "")
+{
+ const size_t is4byteUnit = sizeof(*x) == 4;
+ if (msg) printf("%s ", msg);
+ for (size_t i = 0; i < n; i++) {
+ if (is4byteUnit) {
+ printf("%08x", (uint32_t)x[n - 1 - i]);
+ } else {
+ printf("%016llx", (unsigned long long)x[n - 1 - i]);
+ }
+ }
+ printf("\n");
+}
+
+inline uint64_t make64(uint32_t H, uint32_t L)
+{
+ return ((uint64_t)H << 32) | L;
+}
+
+inline void split64(uint32_t *H, uint32_t *L, uint64_t x)
+{
+ *H = uint32_t(x >> 32);
+ *L = uint32_t(x);
+}
+
+/*
+ [H:L] <= x * y
+ @return L
+*/
+inline uint32_t mulUnit(uint32_t *pH, uint32_t x, uint32_t y)
+{
+ uint64_t t = uint64_t(x) * y;
+ uint32_t L;
+ split64(pH, &L, t);
+ return L;
+}
+#if MCL_SIZEOF_UNIT == 8
+inline uint64_t mulUnit(uint64_t *pH, uint64_t x, uint64_t y)
+{
+#ifdef MCL_VINT_64BIT_PORTABLE
+ uint32_t a = uint32_t(x >> 32);
+ uint32_t b = uint32_t(x);
+ uint32_t c = uint32_t(y >> 32);
+ uint32_t d = uint32_t(y);
+
+ uint64_t ad = uint64_t(d) * a;
+ uint64_t bd = uint64_t(d) * b;
+ uint64_t L = uint32_t(bd);
+ ad += bd >> 32; // [ad:L]
+
+ uint64_t ac = uint64_t(c) * a;
+ uint64_t bc = uint64_t(c) * b;
+ uint64_t H = uint32_t(bc);
+ ac += bc >> 32; // [ac:H]
+ /*
+ adL
+ acH
+ */
+ uint64_t t = (ac << 32) | H;
+ ac >>= 32;
+ H = t + ad;
+ if (H < t) {
+ ac++;
+ }
+ /*
+ ac:H:L
+ */
+ L |= H << 32;
+ H = (ac << 32) | uint32_t(H >> 32);
+ *pH = H;
+ return L;
+#elif defined(_WIN64) && !defined(__INTEL_COMPILER)
+ return _umul128(x, y, pH);
+#else
+ typedef __attribute__((mode(TI))) unsigned int uint128;
+ uint128 t = uint128(x) * y;
+ *pH = uint64_t(t >> 64);
+ return uint64_t(t);
+#endif
+}
+#endif
+
+template<class T>
+void divNM(T *q, size_t qn, T *r, const T *x, size_t xn, const T *y, size_t yn);
+
+/*
+ q = [H:L] / y
+ r = [H:L] % y
+ return q
+*/
+inline uint32_t divUnit(uint32_t *pr, uint32_t H, uint32_t L, uint32_t y)
+{
+ uint64_t t = make64(H, L);
+ uint32_t q = uint32_t(t / y);
+ *pr = uint32_t(t % y);
+ return q;
+}
+#if MCL_SIZEOF_UNIT == 8
+inline uint64_t divUnit(uint64_t *pr, uint64_t H, uint64_t L, uint64_t y)
+{
+#if defined(MCL_VINT_64BIT_PORTABLE)
+ uint32_t px[4] = { uint32_t(L), uint32_t(L >> 32), uint32_t(H), uint32_t(H >> 32) };
+ uint32_t py[2] = { uint32_t(y), uint32_t(y >> 32) };
+ size_t xn = 4;
+ size_t yn = 2;
+ uint32_t q[4];
+ uint32_t r[2];
+ size_t qn = xn - yn + 1;
+ divNM(q, qn, r, px, xn, py, yn);
+ *pr = make64(r[1], r[0]);
+ return make64(q[1], q[0]);
+#elif defined(_MSC_VER)
+ #error "divUnit for uint64_t is not supported"
+#else
+ typedef __attribute__((mode(TI))) unsigned int uint128;
+ uint128 t = (uint128(H) << 64) | L;
+ uint64_t q = uint64_t(t / y);
+ *pr = uint64_t(t % y);
+ return q;
+#endif
+}
+#endif
+
+/*
+ compare x[] and y[]
+ @retval positive if x > y
+ @retval 0 if x == y
+ @retval negative if x < y
+*/
+template<class T>
+int compareNM(const T *x, size_t xn, const T *y, size_t yn)
+{
+ assert(xn > 0 && yn > 0);
+ if (xn != yn) return xn > yn ? 1 : -1;
+ for (int i = (int)xn - 1; i >= 0; i--) {
+ if (x[i] != y[i]) return x[i] > y[i] ? 1 : -1;
+ }
+ return 0;
+}
+
+template<class T>
+void clearN(T *x, size_t n)
+{
+ for (size_t i = 0; i < n; i++) x[i] = 0;
+}
+
+template<class T>
+void copyN(T *y, const T *x, size_t n)
+{
+ for (size_t i = 0; i < n; i++) y[i] = x[i];
+}
+
+/*
+ z[] = x[n] + y[n]
+ @note return 1 if having carry
+ z may be equal to x or y
+*/
+template<class T>
+T addN(T *z, const T *x, const T *y, size_t n)
+{
+ T c = 0;
+ for (size_t i = 0; i < n; i++) {
+ T xc = x[i] + c;
+ if (xc < c) {
+ // x[i] = Unit(-1) and c = 1
+ z[i] = y[i];
+ } else {
+ xc += y[i];
+ c = y[i] > xc ? 1 : 0;
+ z[i] = xc;
+ }
+ }
+ return c;
+}
+
+/*
+ z[] = x[] + y
+*/
+template<class T>
+T addu1(T *z, const T *x, size_t n, T y)
+{
+ assert(n > 0);
+ T t = x[0] + y;
+ z[0] = t;
+ size_t i = 0;
+ if (t >= y) goto EXIT_0;
+ i = 1;
+ for (; i < n; i++) {
+ t = x[i] + 1;
+ z[i] = t;
+ if (t != 0) goto EXIT_0;
+ }
+ return 1;
+EXIT_0:
+ i++;
+ for (; i < n; i++) {
+ z[i] = x[i];
+ }
+ return 0;
+}
+
+/*
+ x[] += y
+*/
+template<class T>
+T addu1(T *x, size_t n, T y)
+{
+ assert(n > 0);
+ T t = x[0] + y;
+ x[0] = t;
+ size_t i = 0;
+ if (t >= y) return 0;
+ i = 1;
+ for (; i < n; i++) {
+ t = x[i] + 1;
+ x[i] = t;
+ if (t != 0) return 0;
+ }
+ return 1;
+}
+/*
+ z[zn] = x[xn] + y[yn]
+ @note zn = max(xn, yn)
+*/
+template<class T>
+T addNM(T *z, const T *x, size_t xn, const T *y, size_t yn)
+{
+ if (yn > xn) {
+ fp::swap_(xn, yn);
+ fp::swap_(x, y);
+ }
+ assert(xn >= yn);
+ size_t max = xn;
+ size_t min = yn;
+ T c = vint::addN(z, x, y, min);
+ if (max > min) {
+ c = vint::addu1(z + min, x + min, max - min, c);
+ }
+ return c;
+}
+
+/*
+ z[] = x[n] - y[n]
+ z may be equal to x or y
+*/
+template<class T>
+T subN(T *z, const T *x, const T *y, size_t n)
+{
+ assert(n > 0);
+ T c = 0;
+ for (size_t i = 0; i < n; i++) {
+ T yc = y[i] + c;
+ if (yc < c) {
+ // y[i] = T(-1) and c = 1
+ z[i] = x[i];
+ } else {
+ c = x[i] < yc ? 1 : 0;
+ z[i] = x[i] - yc;
+ }
+ }
+ return c;
+}
+
+/*
+ out[] = x[n] - y
+*/
+template<class T>
+T subu1(T *z, const T *x, size_t n, T y)
+{
+ assert(n > 0);
+#if 0
+ T t = x[0];
+ z[0] = t - y;
+ size_t i = 0;
+ if (t >= y) goto EXIT_0;
+ i = 1;
+ for (; i < n; i++ ){
+ t = x[i];
+ z[i] = t - 1;
+ if (t != 0) goto EXIT_0;
+ }
+ return 1;
+EXIT_0:
+ i++;
+ for (; i < n; i++) {
+ z[i] = x[i];
+ }
+ return 0;
+#else
+ T c = x[0] < y ? 1 : 0;
+ z[0] = x[0] - y;
+ for (size_t i = 1; i < n; i++) {
+ if (x[i] < c) {
+ z[i] = T(-1);
+ } else {
+ z[i] = x[i] - c;
+ c = 0;
+ }
+ }
+ return c;
+#endif
+}
+
+/*
+ z[xn] = x[xn] - y[yn]
+ @note xn >= yn
+*/
+template<class T>
+T subNM(T *z, const T *x, size_t xn, const T *y, size_t yn)
+{
+ assert(xn >= yn);
+ T c = vint::subN(z, x, y, yn);
+ if (xn > yn) {
+ c = vint::subu1(z + yn, x + yn, xn - yn, c);
+ }
+ return c;
+}
+
+/*
+ z[0..n) = x[0..n) * y
+ return z[n]
+ @note accept z == x
+*/
+template<class T>
+T mulu1(T *z, const T *x, size_t n, T y)
+{
+ assert(n > 0);
+ T H = 0;
+ for (size_t i = 0; i < n; i++) {
+ T t = H;
+ T L = mulUnit(&H, x[i], y);
+ z[i] = t + L;
+ if (z[i] < t) {
+ H++;
+ }
+ }
+ return H; // z[n]
+}
+
+/*
+ z[xn * yn] = x[xn] * y[ym]
+*/
+template<class T>
+static inline void mulNM(T *z, const T *x, size_t xn, const T *y, size_t yn)
+{
+ assert(xn > 0 && yn > 0);
+ if (yn > xn) {
+ fp::swap_(yn, xn);
+ fp::swap_(x, y);
+ }
+ assert(xn >= yn);
+ if (z == x) {
+ T *p = (T*)CYBOZU_ALLOCA(sizeof(T) * xn);
+ copyN(p, x, xn);
+ x = p;
+ }
+ if (z == y) {
+ T *p = (T*)CYBOZU_ALLOCA(sizeof(T) * yn);
+ copyN(p, y, yn);
+ y = p;
+ }
+ z[xn] = vint::mulu1(&z[0], x, xn, y[0]);
+ clearN(z + xn + 1, yn - 1);
+
+ T *t2 = (T*)CYBOZU_ALLOCA(sizeof(T) * (xn + 1));
+ for (size_t i = 1; i < yn; i++) {
+ t2[xn] = vint::mulu1(&t2[0], x, xn, y[i]);
+ vint::addN(&z[i], &z[i], &t2[0], xn + 1);
+ }
+}
+/*
+ out[xn * 2] = x[xn] * x[xn]
+ QQQ : optimize this
+*/
+template<class T>
+static inline void sqrN(T *y, const T *x, size_t xn)
+{
+ mulNM(y, x, xn, x, xn);
+}
+
+/*
+ q[] = x[] / y
+ @retval r = x[] % y
+ accept q == x
+*/
+template<class T>
+T divu1(T *q, const T *x, size_t n, T y)
+{
+ T r = 0;
+ for (int i = (int)n - 1; i >= 0; i--) {
+ q[i] = divUnit(&r, r, x[i], y);
+ }
+ return r;
+}
+/*
+ q[] = x[] / y
+ @retval r = x[] % y
+*/
+template<class T>
+T modu1(const T *x, size_t n, T y)
+{
+ T r = 0;
+ for (int i = (int)n - 1; i >= 0; i--) {
+ divUnit(&r, r, x[i], y);
+ }
+ return r;
+}
+
+/*
+ y[] = x[] << bit
+ 0 < bit < sizeof(T) * 8
+ accept y == x
+*/
+template<class T>
+T shlBit(T *y, const T *x, size_t xn, size_t bit)
+{
+ assert(0 < bit && bit < sizeof(T) * 8);
+ assert(xn > 0);
+ size_t rBit = sizeof(T) * 8 - bit;
+ T keep = x[xn - 1];
+ T prev = keep;
+ for (size_t i = xn - 1; i > 0; i--) {
+ T t = x[i - 1];
+ y[i] = (prev << bit) | (t >> rBit);
+ prev = t;
+ }
+ y[0] = prev << bit;
+ return keep >> rBit;
+}
+
+/*
+ y[yn] = x[xn] << bit
+ yn = xn + (bit + unitBitBit - 1) / unitBitSize
+ accept y == x
+*/
+template<class T>
+void shlN(T *y, const T *x, size_t xn, size_t bit)
+{
+ assert(xn > 0);
+ const size_t unitBitSize = sizeof(T) * 8;
+ size_t q = bit / unitBitSize;
+ size_t r = bit % unitBitSize;
+ if (r == 0) {
+ // don't use copyN(y + q, x, xn); if overlaped
+ for (size_t i = 0; i < xn; i++) {
+ y[q + xn - 1 - i] = x[xn - 1 - i];
+ }
+ } else {
+ y[q + xn] = shlBit(y + q, x, xn, r);
+ }
+ clearN(y, q);
+}
+
+/*
+ y[] = x[] >> bit
+ 0 < bit < sizeof(T) * 8
+*/
+template<class T>
+void shrBit(T *y, const T *x, size_t xn, size_t bit)
+{
+ assert(0 < bit && bit < sizeof(T) * 8);
+ assert(xn > 0);
+ size_t rBit = sizeof(T) * 8 - bit;
+ T prev = x[0];
+ for (size_t i = 1; i < xn; i++) {
+ T t = x[i];
+ y[i - 1] = (prev >> bit) | (t << rBit);
+ prev = t;
+ }
+ y[xn - 1] = prev >> bit;
+}
+/*
+ y[yn] = x[xn] >> bit
+ yn = xn - bit / unitBit
+*/
+template<class T>
+void shrN(T *y, const T *x, size_t xn, size_t bit)
+{
+ assert(xn > 0);
+ const size_t unitBitSize = sizeof(T) * 8;
+ size_t q = bit / unitBitSize;
+ size_t r = bit % unitBitSize;
+ assert(xn >= q);
+ if (r == 0) {
+ copyN(y, x + q, xn - q);
+ } else {
+ shrBit(y, x + q, xn - q, r);
+ }
+}
+
+template<class T>
+size_t getRealSize(const T *x, size_t xn)
+{
+ int i = (int)xn - 1;
+ for (; i > 0; i--) {
+ if (x[i]) {
+ return i + 1;
+ }
+ }
+ return 1;
+}
+
+template<class T>
+size_t getBitSize(const T *x, size_t n)
+{
+ if (n == 1 && x[0] == 0) return 1;
+ T v = x[n - 1];
+ assert(v);
+ return (n - 1) * sizeof(T) * 8 + 1 + cybozu::bsr<Unit>(v);
+}
+
+/*
+ q[qn] = x[xn] / y[yn] ; qn == xn - yn + 1 if xn >= yn if q
+ r[rn] = x[xn] % y[yn] ; rn = yn before getRealSize
+ allow q == 0
+*/
+template<class T>
+void divNM(T *q, size_t qn, T *r, const T *x, size_t xn, const T *y, size_t yn)
+{
+ assert(xn > 0 && yn > 0);
+ assert(xn < yn || (q == 0 || qn == xn - yn + 1));
+ assert(q != r);
+ const size_t rn = yn;
+ xn = getRealSize(x, xn);
+ yn = getRealSize(y, yn);
+ if (x == y) {
+ assert(xn == yn);
+ x_is_y:
+ clearN(r, rn);
+ if (q) {
+ q[0] = 1;
+ clearN(q + 1, qn - 1);
+ }
+ return;
+ }
+ if (yn > xn) {
+ /*
+ if y > x then q = 0 and r = x
+ */
+ q_is_zero:
+ copyN(r, x, xn);
+ clearN(r + xn, rn - xn);
+ if (q) clearN(q, qn);
+ return;
+ }
+ if (yn == 1) {
+ T t;
+ if (q) {
+ if (qn > xn) {
+ clearN(q + xn, qn - xn);
+ }
+ t = divu1(q, x, xn, y[0]);
+ } else {
+ t = modu1(x, xn, y[0]);
+ }
+ r[0] = t;
+ clearN(r + 1, rn - 1);
+ return;
+ }
+ const size_t yTopBit = cybozu::bsr(y[yn - 1]);
+ assert(yn >= 2);
+ if (xn == yn) {
+ const size_t xTopBit = cybozu::bsr(x[xn - 1]);
+ if (xTopBit < yTopBit) goto q_is_zero;
+ if (yTopBit == xTopBit) {
+ int ret = compareNM(x, xn, y, yn);
+ if (ret == 0) goto x_is_y;
+ if (ret < 0) goto q_is_zero;
+ if (r) {
+ subN(r, x, y, yn);
+ }
+ if (q) {
+ q[0] = 1;
+ clearN(q + 1, qn - 1);
+ }
+ return;
+ }
+ assert(xTopBit > yTopBit);
+ // fast reduction for larger than fullbit-3 size p
+ if (yTopBit >= sizeof(T) * 8 - 4) {
+ T *xx = (T*)CYBOZU_ALLOCA(sizeof(T) * xn);
+ T qv = 0;
+ if (yTopBit == sizeof(T) * 8 - 2) {
+ copyN(xx, x, xn);
+ } else {
+ qv = x[xn - 1] >> (yTopBit + 1);
+ mulu1(xx, y, yn, qv);
+ subN(xx, x, xx, xn);
+ xn = getRealSize(xx, xn);
+ }
+ for (;;) {
+ T ret = subN(xx, xx, y, yn);
+ if (ret) {
+ addN(xx, xx, y, yn);
+ break;
+ }
+ qv++;
+ xn = getRealSize(xx, xn);
+ }
+ if (r) {
+ copyN(r, xx, xn);
+ clearN(r + xn, rn - xn);
+ }
+ if (q) {
+ q[0] = qv;
+ clearN(q + 1, qn - 1);
+ }
+ return;
+ }
+ }
+ /*
+ bitwise left shift x and y to adjust MSB of y[yn - 1] = 1
+ */
+ const size_t shift = sizeof(T) * 8 - 1 - yTopBit;
+ T *xx = (T*)CYBOZU_ALLOCA(sizeof(T) * (xn + 1));
+ const T *yy;
+ if (shift) {
+ T v = shlBit(xx, x, xn, shift);
+ if (v) {
+ xx[xn] = v;
+ xn++;
+ }
+ T *yBuf = (T*)CYBOZU_ALLOCA(sizeof(T) * yn);
+ shlBit(yBuf, y, yn ,shift);
+ yy = yBuf;
+ } else {
+ copyN(xx, x, xn);
+ yy = y;
+ }
+ if (q) {
+ clearN(q, qn);
+ }
+ assert((yy[yn - 1] >> (sizeof(T) * 8 - 1)) != 0);
+ T *tt = (T*)CYBOZU_ALLOCA(sizeof(T) * (yn + 1));
+ while (xn > yn) {
+ size_t d = xn - yn;
+ T xTop = xx[xn - 1];
+ T yTop = yy[yn - 1];
+ if (xTop > yTop || (compareNM(xx + d, xn - d, yy, yn) >= 0)) {
+ vint::subN(xx + d, xx + d, yy, yn);
+ xn = getRealSize(xx, xn);
+ if (q) vint::addu1<T>(q + d, qn - d, 1);
+ continue;
+ }
+ if (xTop == 1) {
+ vint::subNM(xx + d - 1, xx + d - 1, xn - d + 1, yy, yn);
+ xn = getRealSize(xx, xn);
+ if (q) vint::addu1<T>(q + d - 1, qn - d + 1, 1);
+ continue;
+ }
+ tt[yn] = vint::mulu1(tt, yy, yn, xTop);
+ vint::subN(xx + d - 1, xx + d - 1, tt, yn + 1);
+ xn = getRealSize(xx, xn);
+ if (q) vint::addu1<T>(q + d - 1, qn - d + 1, xTop);
+ }
+ if (xn == yn && compareNM(xx, xn, yy, yn) >= 0) {
+ subN(xx, xx, yy, yn);
+ xn = getRealSize(xx, xn);
+ if (q) vint::addu1<T>(q, qn, 1);
+ }
+ if (shift) {
+ shrBit(r, xx, xn, shift);
+ } else {
+ copyN(r, xx, xn);
+ }
+ clearN(r + xn, rn - xn);
+}
+
+#ifndef MCL_VINT_FIXED_BUFFER
+template<class T>
+class Buffer {
+ size_t allocSize_;
+ T *ptr_;
+public:
+ typedef T Unit;
+ Buffer() : allocSize_(0), ptr_(0) {}
+ ~Buffer()
+ {
+ clear();
+ }
+ Buffer(const Buffer& rhs)
+ : allocSize_(rhs.allocSize_)
+ , ptr_(0)
+ {
+ ptr_ = (T*)malloc(allocSize_ * sizeof(T));
+ if (ptr_ == 0) throw cybozu::Exception("Buffer:malloc") << rhs.allocSize_;
+ memcpy(ptr_, rhs.ptr_, allocSize_ * sizeof(T));
+ }
+ Buffer& operator=(const Buffer& rhs)
+ {
+ Buffer t(rhs);
+ swap(t);
+ return *this;
+ }
+ void swap(Buffer& rhs)
+#if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11
+ noexcept
+#endif
+ {
+ fp::swap_(allocSize_, rhs.allocSize_);
+ fp::swap_(ptr_, rhs.ptr_);
+ }
+ void clear()
+ {
+ allocSize_ = 0;
+ free(ptr_);
+ ptr_ = 0;
+ }
+
+ /*
+ @note extended buffer may be not cleared
+ */
+ void alloc(bool *pb, size_t n)
+ {
+ if (n > allocSize_) {
+ T *p = (T*)malloc(n * sizeof(T));
+ if (p == 0) {
+ *pb = false;
+ return;
+ }
+ copyN(p, ptr_, allocSize_);
+ free(ptr_);
+ ptr_ = p;
+ allocSize_ = n;
+ }
+ *pb = true;
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ void alloc(size_t n)
+ {
+ bool b;
+ alloc(&b, n);
+ if (!b) throw cybozu::Exception("Buffer:alloc");
+ }
+#endif
+ /*
+ *this = rhs
+ rhs may be destroyed
+ */
+ const T& operator[](size_t n) const { return ptr_[n]; }
+ T& operator[](size_t n) { return ptr_[n]; }
+};
+#endif
+
+template<class T, size_t BitLen>
+class FixedBuffer {
+ enum {
+ N = (BitLen + sizeof(T) * 8 - 1) / (sizeof(T) * 8)
+ };
+ size_t size_;
+ T v_[N];
+public:
+ typedef T Unit;
+ FixedBuffer()
+ : size_(0)
+ {
+ }
+ FixedBuffer(const FixedBuffer& rhs)
+ {
+ operator=(rhs);
+ }
+ FixedBuffer& operator=(const FixedBuffer& rhs)
+ {
+ size_ = rhs.size_;
+ for (size_t i = 0; i < size_; i++) {
+ v_[i] = rhs.v_[i];
+ }
+ return *this;
+ }
+ void clear() { size_ = 0; }
+ void alloc(bool *pb, size_t n)
+ {
+ if (n > N) {
+ *pb = false;
+ return;
+ }
+ size_ = n;
+ *pb = true;
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ void alloc(size_t n)
+ {
+ bool b;
+ alloc(&b, n);
+ if (!b) throw cybozu::Exception("FixedBuffer:alloc");
+ }
+#endif
+ void swap(FixedBuffer& rhs)
+ {
+ FixedBuffer *p1 = this;
+ FixedBuffer *p2 = &rhs;
+ if (p1->size_ < p2->size_) {
+ fp::swap_(p1, p2);
+ }
+ assert(p1->size_ >= p2->size_);
+ for (size_t i = 0; i < p2->size_; i++) {
+ fp::swap_(p1->v_[i], p2->v_[i]);
+ }
+ for (size_t i = p2->size_; i < p1->size_; i++) {
+ p2->v_[i] = p1->v_[i];
+ }
+ fp::swap_(p1->size_, p2->size_);
+ }
+ // to avoid warning of gcc
+ void verify(size_t n) const
+ {
+ assert(n <= N);
+ (void)n;
+ }
+ const T& operator[](size_t n) const { verify(n); return v_[n]; }
+ T& operator[](size_t n) { verify(n); return v_[n]; }
+};
+
+#if MCL_SIZEOF_UNIT == 8
+/*
+ M = 1 << 256
+ a = M mod p = (1 << 32) + 0x3d1
+ [H:L] mod p = H * a + L
+
+ if H = L = M - 1, t = H * a + L = aM + (M - a - 1)
+ H' = a, L' = M - a - 1
+ t' = H' * a + L' = M + (a^2 - a - 1)
+ H'' = 1, L'' = a^2 - a - 1
+ t'' = H'' * a + L'' = a^2 - 1
+*/
+inline void mcl_fpDbl_mod_SECP256K1(Unit *z, const Unit *x, const Unit *p)
+{
+ const Unit a = (uint64_t(1) << 32) + 0x3d1;
+ Unit buf[5];
+ buf[4] = mulu1(buf, x + 4, 4, a); // H * a
+ buf[4] += addN(buf, buf, x, 4); // t = H * a + L
+ Unit x2[2];
+ x2[0] = mulUnit(&x2[1], buf[4], a);
+ Unit x3 = addN(buf, buf, x2, 2);
+ if (x3) {
+ x3 = addu1(buf + 2, buf + 2, 2, Unit(1)); // t' = H' * a + L'
+ if (x3) {
+ x3 = addu1(buf, buf, 4, a);
+ assert(x3 == 0);
+ }
+ }
+ if (fp::isGreaterOrEqualArray(buf, p, 4)) {
+ subN(z, buf, p, 4);
+ } else {
+ fp::copyArray(z, buf, 4);
+ }
+}
+
+inline void mcl_fp_mul_SECP256K1(Unit *z, const Unit *x, const Unit *y, const Unit *p)
+{
+ Unit xy[8];
+ mulNM(xy, x, 4, y, 4);
+ mcl_fpDbl_mod_SECP256K1(z, xy, p);
+}
+inline void mcl_fp_sqr_SECP256K1(Unit *y, const Unit *x, const Unit *p)
+{
+ Unit xx[8];
+ sqrN(xx, x, 4);
+ mcl_fpDbl_mod_SECP256K1(y, xx, p);
+}
+#endif
+
+} // vint
+
+/**
+ signed integer with variable length
+*/
+template<class _Buffer>
+class VintT {
+public:
+ typedef _Buffer Buffer;
+ typedef typename Buffer::Unit Unit;
+ static const size_t unitBitSize = sizeof(Unit) * 8;
+ static const int invalidVar = -2147483647 - 1; // abs(invalidVar) is not defined
+private:
+ Buffer buf_;
+ size_t size_;
+ bool isNeg_;
+ void trim(size_t n)
+ {
+ assert(n > 0);
+ int i = (int)n - 1;
+ for (; i > 0; i--) {
+ if (buf_[i]) {
+ size_ = i + 1;
+ return;
+ }
+ }
+ size_ = 1;
+ // zero
+ if (buf_[0] == 0) {
+ isNeg_ = false;
+ }
+ }
+ static int ucompare(const Buffer& x, size_t xn, const Buffer& y, size_t yn)
+ {
+ return vint::compareNM(&x[0], xn, &y[0], yn);
+ }
+ static void uadd(VintT& z, const Buffer& x, size_t xn, const Buffer& y, size_t yn)
+ {
+ size_t zn = fp::max_(xn, yn) + 1;
+ bool b;
+ z.buf_.alloc(&b, zn);
+ assert(b); (void)b;
+ z.buf_[zn - 1] = vint::addNM(&z.buf_[0], &x[0], xn, &y[0], yn);
+ z.trim(zn);
+ }
+ static void uadd1(VintT& z, const Buffer& x, size_t xn, Unit y)
+ {
+ size_t zn = xn + 1;
+ bool b;
+ z.buf_.alloc(&b, zn);
+ assert(b); (void)b;
+ z.buf_[zn - 1] = vint::addu1(&z.buf_[0], &x[0], xn, y);
+ z.trim(zn);
+ }
+ static void usub1(VintT& z, const Buffer& x, size_t xn, Unit y)
+ {
+ size_t zn = xn;
+ bool b;
+ z.buf_.alloc(&b, zn);
+ assert(b); (void)b;
+ Unit c = vint::subu1(&z.buf_[0], &x[0], xn, y);
+ (void)c;
+ assert(!c);
+ z.trim(zn);
+ }
+ static void usub(VintT& z, const Buffer& x, size_t xn, const Buffer& y, size_t yn)
+ {
+ assert(xn >= yn);
+ bool b;
+ z.buf_.alloc(&b, xn);
+ assert(b); (void)b;
+ Unit c = vint::subN(&z.buf_[0], &x[0], &y[0], yn);
+ if (xn > yn) {
+ c = vint::subu1(&z.buf_[yn], &x[yn], xn - yn, c);
+ }
+ assert(!c);
+ z.trim(xn);
+ }
+ static void _add(VintT& z, const VintT& x, bool xNeg, const VintT& y, bool yNeg)
+ {
+ if ((xNeg ^ yNeg) == 0) {
+ // same sign
+ uadd(z, x.buf_, x.size(), y.buf_, y.size());
+ z.isNeg_ = xNeg;
+ return;
+ }
+ int r = ucompare(x.buf_, x.size(), y.buf_, y.size());
+ if (r >= 0) {
+ usub(z, x.buf_, x.size(), y.buf_, y.size());
+ z.isNeg_ = xNeg;
+ } else {
+ usub(z, y.buf_, y.size(), x.buf_, x.size());
+ z.isNeg_ = yNeg;
+ }
+ }
+ static void _adds1(VintT& z, const VintT& x, int y, bool yNeg)
+ {
+ assert(y >= 0);
+ if ((x.isNeg_ ^ yNeg) == 0) {
+ // same sign
+ uadd1(z, x.buf_, x.size(), y);
+ z.isNeg_ = yNeg;
+ return;
+ }
+ if (x.size() > 1 || x.buf_[0] >= (Unit)y) {
+ usub1(z, x.buf_, x.size(), y);
+ z.isNeg_ = x.isNeg_;
+ } else {
+ z = y - x.buf_[0];
+ z.isNeg_ = yNeg;
+ }
+ }
+ static void _addu1(VintT& z, const VintT& x, Unit y, bool yNeg)
+ {
+ if ((x.isNeg_ ^ yNeg) == 0) {
+ // same sign
+ uadd1(z, x.buf_, x.size(), y);
+ z.isNeg_ = yNeg;
+ return;
+ }
+ if (x.size() > 1 || x.buf_[0] >= y) {
+ usub1(z, x.buf_, x.size(), y);
+ z.isNeg_ = x.isNeg_;
+ } else {
+ z = y - x.buf_[0];
+ z.isNeg_ = yNeg;
+ }
+ }
+ /**
+ @param q [out] x / y if q != 0
+ @param r [out] x % y
+ */
+ static void udiv(VintT* q, VintT& r, const Buffer& x, size_t xn, const Buffer& y, size_t yn)
+ {
+ assert(q != &r);
+ if (xn < yn) {
+ r.buf_ = x;
+ r.trim(xn);
+ if (q) q->clear();
+ return;
+ }
+ size_t qn = xn - yn + 1;
+ bool b;
+ if (q) {
+ q->buf_.alloc(&b, qn);
+ assert(b); (void)b;
+ }
+ r.buf_.alloc(&b, yn);
+ assert(b); (void)b;
+ vint::divNM(q ? &q->buf_[0] : 0, qn, &r.buf_[0], &x[0], xn, &y[0], yn);
+ if (q) {
+ q->trim(qn);
+ }
+ r.trim(yn);
+ }
+ /*
+ @param x [inout] x <- d
+ @retval s for x = 2^s d where d is odd
+ */
+ static uint32_t countTrailingZero(VintT& x)
+ {
+ uint32_t s = 0;
+ while (x.isEven()) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+ struct MulMod {
+ const VintT *pm;
+ void operator()(VintT& z, const VintT& x, const VintT& y) const
+ {
+ VintT::mul(z, x, y);
+ z %= *pm;
+ }
+ };
+ struct SqrMod {
+ const VintT *pm;
+ void operator()(VintT& y, const VintT& x) const
+ {
+ VintT::sqr(y, x);
+ y %= *pm;
+ }
+ };
+public:
+ VintT(int x = 0)
+ : size_(0)
+ {
+ *this = x;
+ }
+ VintT(Unit x)
+ : size_(0)
+ {
+ *this = x;
+ }
+ VintT(const VintT& rhs)
+ : buf_(rhs.buf_)
+ , size_(rhs.size_)
+ , isNeg_(rhs.isNeg_)
+ {
+ }
+ VintT& operator=(int x)
+ {
+ assert(x != invalidVar);
+ isNeg_ = x < 0;
+ bool b;
+ buf_.alloc(&b, 1);
+ assert(b); (void)b;
+ buf_[0] = fp::abs_(x);
+ size_ = 1;
+ return *this;
+ }
+ VintT& operator=(Unit x)
+ {
+ isNeg_ = false;
+ bool b;
+ buf_.alloc(&b, 1);
+ assert(b); (void)b;
+ buf_[0] = x;
+ size_ = 1;
+ return *this;
+ }
+ VintT& operator=(const VintT& rhs)
+ {
+ buf_ = rhs.buf_;
+ size_ = rhs.size_;
+ isNeg_ = rhs.isNeg_;
+ return *this;
+ }
+#if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11
+ VintT(VintT&& rhs)
+ : buf_(rhs.buf_)
+ , size_(rhs.size_)
+ , isNeg_(rhs.isNeg_)
+ {
+ }
+ VintT& operator=(VintT&& rhs)
+ {
+ buf_ = std::move(rhs.buf_);
+ size_ = rhs.size_;
+ isNeg_ = rhs.isNeg_;
+ return *this;
+ }
+#endif
+ void swap(VintT& rhs)
+#if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11
+ noexcept
+#endif
+ {
+ fp::swap_(buf_, rhs.buf_);
+ fp::swap_(size_, rhs.size_);
+ fp::swap_(isNeg_, rhs.isNeg_);
+ }
+ void dump(const char *msg = "") const
+ {
+ vint::dump(&buf_[0], size_, msg);
+ }
+ /*
+ set positive value
+ @note assume little endian system
+ */
+ template<class S>
+ void setArray(bool *pb, const S *x, size_t size)
+ {
+ isNeg_ = false;
+ if (size == 0) {
+ clear();
+ *pb = true;
+ return;
+ }
+ size_t unitSize = (sizeof(S) * size + sizeof(Unit) - 1) / sizeof(Unit);
+ buf_.alloc(pb, unitSize);
+ if (!*pb) return;
+ char *dst = (char *)&buf_[0];
+ const char *src = (const char *)x;
+ size_t i = 0;
+ for (; i < sizeof(S) * size; i++) {
+ dst[i] = src[i];
+ }
+ for (; i < sizeof(Unit) * unitSize; i++) {
+ dst[i] = 0;
+ }
+ trim(unitSize);
+ }
+ /*
+ set [0, max) randomly
+ */
+ void setRand(bool *pb, const VintT& max, fp::RandGen rg = fp::RandGen())
+ {
+ assert(max > 0);
+ if (rg.isZero()) rg = fp::RandGen::get();
+ size_t n = max.size();
+ buf_.alloc(pb, n);
+ if (!*pb) return;
+ rg.read(pb, &buf_[0], n * sizeof(buf_[0]));
+ if (!*pb) return;
+ trim(n);
+ *this %= max;
+ }
+ /*
+ get abs value
+ buf_[0, size) = x
+ buf_[size, maxSize) with zero
+ @note assume little endian system
+ */
+ void getArray(bool *pb, Unit *x, size_t maxSize) const
+ {
+ size_t n = size();
+ if (n > maxSize) {
+ *pb = false;
+ return;
+ }
+ vint::copyN(x, &buf_[0], n);
+ vint::clearN(x + n, maxSize - n);
+ *pb = true;
+ }
+ void clear() { *this = 0; }
+ template<class OutputStream>
+ void save(bool *pb, OutputStream& os, int base = 10) const
+ {
+ if (isNeg_) cybozu::writeChar(pb, os, '-');
+ char buf[1024];
+ size_t n = mcl::fp::arrayToStr(buf, sizeof(buf), &buf_[0], size_, base, false);
+ if (n == 0) {
+ *pb = false;
+ return;
+ }
+ cybozu::write(pb, os, buf + sizeof(buf) - n, n);
+ }
+ /*
+ set buf with string terminated by '\0'
+ return strlen(buf) if success else 0
+ */
+ size_t getStr(char *buf, size_t bufSize, int base = 10) const
+ {
+ cybozu::MemoryOutputStream os(buf, bufSize);
+ bool b;
+ save(&b, os, base);
+ const size_t n = os.getPos();
+ if (!b || n == bufSize) return 0;
+ buf[n] = '\0';
+ return n;
+ }
+ /*
+ return bitSize(abs(*this))
+ @note return 1 if zero
+ */
+ size_t getBitSize() const
+ {
+ if (isZero()) return 1;
+ size_t n = size();
+ Unit v = buf_[n - 1];
+ assert(v);
+ return (n - 1) * sizeof(Unit) * 8 + 1 + cybozu::bsr<Unit>(v);
+ }
+ // ignore sign
+ bool testBit(size_t i) const
+ {
+ size_t q = i / unitBitSize;
+ size_t r = i % unitBitSize;
+ assert(q <= size());
+ Unit mask = Unit(1) << r;
+ return (buf_[q] & mask) != 0;
+ }
+ void setBit(size_t i, bool v = true)
+ {
+ size_t q = i / unitBitSize;
+ size_t r = i % unitBitSize;
+ assert(q <= size());
+ bool b;
+ buf_.alloc(&b, q + 1);
+ assert(b); (void)b;
+ Unit mask = Unit(1) << r;
+ if (v) {
+ buf_[q] |= mask;
+ } else {
+ buf_[q] &= ~mask;
+ trim(q + 1);
+ }
+ }
+ /*
+ @param str [in] number string
+ @note "0x..." => base = 16
+ "0b..." => base = 2
+ otherwise => base = 10
+ */
+ void setStr(bool *pb, const char *str, int base = 0)
+ {
+ // allow twice size of MCL_MAX_BIT_SIZE because of multiplication
+ const size_t maxN = (MCL_MAX_BIT_SIZE * 2 + unitBitSize - 1) / unitBitSize;
+ buf_.alloc(pb, maxN);
+ if (!*pb) return;
+ *pb = false;
+ isNeg_ = false;
+ size_t len = strlen(str);
+ size_t n = fp::strToArray(&isNeg_, &buf_[0], maxN, str, len, base);
+ if (n == 0) return;
+ trim(n);
+ *pb = true;
+ }
+ static int compare(const VintT& x, const VintT& y)
+ {
+ if (x.isNeg_ ^ y.isNeg_) {
+ if (x.isZero() && y.isZero()) return 0;
+ return x.isNeg_ ? -1 : 1;
+ } else {
+ // same sign
+ int c = ucompare(x.buf_, x.size(), y.buf_, y.size());
+ if (x.isNeg_) {
+ return -c;
+ }
+ return c;
+ }
+ }
+ static int compares1(const VintT& x, int y)
+ {
+ assert(y != invalidVar);
+ if (x.isNeg_ ^ (y < 0)) {
+ if (x.isZero() && y == 0) return 0;
+ return x.isNeg_ ? -1 : 1;
+ } else {
+ // same sign
+ Unit y0 = fp::abs_(y);
+ int c = vint::compareNM(&x.buf_[0], x.size(), &y0, 1);
+ if (x.isNeg_) {
+ return -c;
+ }
+ return c;
+ }
+ }
+ static int compareu1(const VintT& x, uint32_t y)
+ {
+ if (x.isNeg_) return -1;
+ if (x.size() > 1) return 1;
+ Unit x0 = x.buf_[0];
+ return x0 > y ? 1 : x0 == y ? 0 : -1;
+ }
+ size_t size() const { return size_; }
+ bool isZero() const { return size() == 1 && buf_[0] == 0; }
+ bool isNegative() const { return !isZero() && isNeg_; }
+ uint32_t getLow32bit() const { return (uint32_t)buf_[0]; }
+ bool isOdd() const { return (buf_[0] & 1) == 1; }
+ bool isEven() const { return !isOdd(); }
+ const Unit *getUnit() const { return &buf_[0]; }
+ size_t getUnitSize() const { return size_; }
+ static void add(VintT& z, const VintT& x, const VintT& y)
+ {
+ _add(z, x, x.isNeg_, y, y.isNeg_);
+ }
+ static void sub(VintT& z, const VintT& x, const VintT& y)
+ {
+ _add(z, x, x.isNeg_, y, !y.isNeg_);
+ }
+ static void mul(VintT& z, const VintT& x, const VintT& y)
+ {
+ const size_t xn = x.size();
+ const size_t yn = y.size();
+ size_t zn = xn + yn;
+ bool b;
+ z.buf_.alloc(&b, zn);
+ assert(b); (void)b;
+ vint::mulNM(&z.buf_[0], &x.buf_[0], xn, &y.buf_[0], yn);
+ z.isNeg_ = x.isNeg_ ^ y.isNeg_;
+ z.trim(zn);
+ }
+ static void sqr(VintT& y, const VintT& x)
+ {
+ mul(y, x, x);
+ }
+ static void addu1(VintT& z, const VintT& x, Unit y)
+ {
+ _addu1(z, x, y, false);
+ }
+ static void subu1(VintT& z, const VintT& x, Unit y)
+ {
+ _addu1(z, x, y, true);
+ }
+ static void mulu1(VintT& z, const VintT& x, Unit y)
+ {
+ size_t xn = x.size();
+ size_t zn = xn + 1;
+ bool b;
+ z.buf_.alloc(&b, zn);
+ assert(b); (void)b;
+ z.buf_[zn - 1] = vint::mulu1(&z.buf_[0], &x.buf_[0], xn, y);
+ z.isNeg_ = x.isNeg_;
+ z.trim(zn);
+ }
+ static void divu1(VintT& q, const VintT& x, Unit y)
+ {
+ udivModu1(&q, x, y);
+ }
+ static void modu1(VintT& r, const VintT& x, Unit y)
+ {
+ bool xNeg = x.isNeg_;
+ r = divModu1(0, x, y);
+ r.isNeg_ = xNeg;
+ }
+ static void adds1(VintT& z, const VintT& x, int y)
+ {
+ assert(y != invalidVar);
+ _adds1(z, x, fp::abs_(y), y < 0);
+ }
+ static void subs1(VintT& z, const VintT& x, int y)
+ {
+ assert(y != invalidVar);
+ _adds1(z, x, fp::abs_(y), !(y < 0));
+ }
+ static void muls1(VintT& z, const VintT& x, int y)
+ {
+ assert(y != invalidVar);
+ mulu1(z, x, fp::abs_(y));
+ z.isNeg_ ^= (y < 0);
+ }
+ /*
+ @param q [out] q = x / y if q is not zero
+ @param x [in]
+ @param y [in] must be not zero
+ return x % y
+ */
+ static int divMods1(VintT *q, const VintT& x, int y)
+ {
+ assert(y != invalidVar);
+ bool xNeg = x.isNeg_;
+ bool yNeg = y < 0;
+ Unit absY = fp::abs_(y);
+ size_t xn = x.size();
+ int r;
+ if (q) {
+ q->isNeg_ = xNeg ^ yNeg;
+ bool b;
+ q->buf_.alloc(&b, xn);
+ assert(b); (void)b;
+ r = (int)vint::divu1(&q->buf_[0], &x.buf_[0], xn, absY);
+ q->trim(xn);
+ } else {
+ r = (int)vint::modu1(&x.buf_[0], xn, absY);
+ }
+ return xNeg ? -r : r;
+ }
+ /*
+ like C
+ 13 / 5 = 2 ... 3
+ 13 / -5 = -2 ... 3
+ -13 / 5 = -2 ... -3
+ -13 / -5 = 2 ... -3
+ */
+ static void divMod(VintT *q, VintT& r, const VintT& x, const VintT& y)
+ {
+ bool qsign = x.isNeg_ ^ y.isNeg_;
+ udiv(q, r, x.buf_, x.size(), y.buf_, y.size());
+ r.isNeg_ = x.isNeg_;
+ if (q) q->isNeg_ = qsign;
+ }
+ static void div(VintT& q, const VintT& x, const VintT& y)
+ {
+ VintT r;
+ divMod(&q, r, x, y);
+ }
+ static void mod(VintT& r, const VintT& x, const VintT& y)
+ {
+ divMod(0, r, x, y);
+ }
+ static void divs1(VintT& q, const VintT& x, int y)
+ {
+ divMods1(&q, x, y);
+ }
+ static void mods1(VintT& r, const VintT& x, int y)
+ {
+ bool xNeg = x.isNeg_;
+ r = divMods1(0, x, y);
+ r.isNeg_ = xNeg;
+ }
+ static Unit udivModu1(VintT *q, const VintT& x, Unit y)
+ {
+ assert(!x.isNeg_);
+ size_t xn = x.size();
+ if (q) {
+ bool b;
+ q->buf_.alloc(&b, xn);
+ assert(b); (void)b;
+ }
+ Unit r = vint::divu1(q ? &q->buf_[0] : 0, &x.buf_[0], xn, y);
+ if (q) {
+ q->trim(xn);
+ q->isNeg_ = false;
+ }
+ return r;
+ }
+ /*
+ like Python
+ 13 / 5 = 2 ... 3
+ 13 / -5 = -3 ... -2
+ -13 / 5 = -3 ... 2
+ -13 / -5 = 2 ... -3
+ */
+ static void quotRem(VintT *q, VintT& r, const VintT& x, const VintT& y)
+ {
+ VintT yy = y;
+ bool qsign = x.isNeg_ ^ y.isNeg_;
+ udiv(q, r, x.buf_, x.size(), y.buf_, y.size());
+ r.isNeg_ = y.isNeg_;
+ if (q) q->isNeg_ = qsign;
+ if (!r.isZero() && qsign) {
+ if (q) {
+ uadd1(*q, q->buf_, q->size(), 1);
+ }
+ usub(r, yy.buf_, yy.size(), r.buf_, r.size());
+ }
+ }
+ template<class InputStream>
+ void load(bool *pb, InputStream& is, int ioMode)
+ {
+ *pb = false;
+ char buf[1024];
+ size_t n = fp::local::loadWord(buf, sizeof(buf), is);
+ if (n == 0) return;
+ const size_t maxN = 384 / (sizeof(MCL_SIZEOF_UNIT) * 8);
+ buf_.alloc(pb, maxN);
+ if (!*pb) return;
+ isNeg_ = false;
+ n = fp::strToArray(&isNeg_, &buf_[0], maxN, buf, n, ioMode);
+ if (n == 0) return;
+ trim(n);
+ *pb = true;
+ }
+ // logical left shift (copy sign)
+ static void shl(VintT& y, const VintT& x, size_t shiftBit)
+ {
+ size_t xn = x.size();
+ size_t yn = xn + (shiftBit + unitBitSize - 1) / unitBitSize;
+ bool b;
+ y.buf_.alloc(&b, yn);
+ assert(b); (void)b;
+ vint::shlN(&y.buf_[0], &x.buf_[0], xn, shiftBit);
+ y.isNeg_ = x.isNeg_;
+ y.trim(yn);
+ }
+ // logical right shift (copy sign)
+ static void shr(VintT& y, const VintT& x, size_t shiftBit)
+ {
+ size_t xn = x.size();
+ if (xn * unitBitSize <= shiftBit) {
+ y.clear();
+ return;
+ }
+ size_t yn = xn - shiftBit / unitBitSize;
+ bool b;
+ y.buf_.alloc(&b, yn);
+ assert(b); (void)b;
+ vint::shrN(&y.buf_[0], &x.buf_[0], xn, shiftBit);
+ y.isNeg_ = x.isNeg_;
+ y.trim(yn);
+ }
+ static void neg(VintT& y, const VintT& x)
+ {
+ if (&y != &x) { y = x; }
+ y.isNeg_ = !x.isNeg_;
+ }
+ static void abs(VintT& y, const VintT& x)
+ {
+ if (&y != &x) { y = x; }
+ y.isNeg_ = false;
+ }
+ static VintT abs(const VintT& x)
+ {
+ VintT y = x;
+ abs(y, x);
+ return y;
+ }
+ // accept only non-negative value
+ static void orBit(VintT& z, const VintT& x, const VintT& y)
+ {
+ assert(!x.isNeg_ && !y.isNeg_);
+ const VintT *px = &x, *py = &y;
+ if (x.size() < y.size()) {
+ fp::swap_(px, py);
+ }
+ size_t xn = px->size();
+ size_t yn = py->size();
+ assert(xn >= yn);
+ bool b;
+ z.buf_.alloc(&b, xn);
+ assert(b); (void)b;
+ for (size_t i = 0; i < yn; i++) {
+ z.buf_[i] = x.buf_[i] | y.buf_[i];
+ }
+ vint::copyN(&z.buf_[0] + yn, &px->buf_[0] + yn, xn - yn);
+ z.trim(xn);
+ }
+ static void andBit(VintT& z, const VintT& x, const VintT& y)
+ {
+ assert(!x.isNeg_ && !y.isNeg_);
+ const VintT *px = &x, *py = &y;
+ if (x.size() < y.size()) {
+ fp::swap_(px, py);
+ }
+ size_t yn = py->size();
+ assert(px->size() >= yn);
+ bool b;
+ z.buf_.alloc(&b, yn);
+ assert(b); (void)b;
+ for (size_t i = 0; i < yn; i++) {
+ z.buf_[i] = x.buf_[i] & y.buf_[i];
+ }
+ z.trim(yn);
+ }
+ static void orBitu1(VintT& z, const VintT& x, Unit y)
+ {
+ assert(!x.isNeg_);
+ z = x;
+ z.buf_[0] |= y;
+ }
+ static void andBitu1(VintT& z, const VintT& x, Unit y)
+ {
+ assert(!x.isNeg_);
+ bool b;
+ z.buf_.alloc(&b, 1);
+ assert(b); (void)b;
+ z.buf_[0] = x.buf_[0] & y;
+ z.size_ = 1;
+ z.isNeg_ = false;
+ }
+ /*
+ REMARK y >= 0;
+ */
+ static void pow(VintT& z, const VintT& x, const VintT& y)
+ {
+ assert(!y.isNeg_);
+ const VintT xx = x;
+ z = 1;
+ mcl::fp::powGeneric(z, xx, &y.buf_[0], y.size(), mul, sqr, (void (*)(VintT&, const VintT&))0);
+ }
+ /*
+ REMARK y >= 0;
+ */
+ static void pow(VintT& z, const VintT& x, int64_t y)
+ {
+ assert(y >= 0);
+ const VintT xx = x;
+ z = 1;
+#if MCL_SIZEOF_UNIT == 8
+ Unit ua = fp::abs_(y);
+ mcl::fp::powGeneric(z, xx, &ua, 1, mul, sqr, (void (*)(VintT&, const VintT&))0);
+#else
+ uint64_t ua = fp::abs_(y);
+ Unit u[2] = { uint32_t(ua), uint32_t(ua >> 32) };
+ size_t un = u[1] ? 2 : 1;
+ mcl::fp::powGeneric(z, xx, u, un, mul, sqr, (void (*)(VintT&, const VintT&))0);
+#endif
+ }
+ /*
+ z = x ^ y mod m
+ REMARK y >= 0;
+ */
+ static void powMod(VintT& z, const VintT& x, const VintT& y, const VintT& m)
+ {
+ assert(!y.isNeg_);
+ VintT zz;
+ MulMod mulMod;
+ SqrMod sqrMod;
+ mulMod.pm = &m;
+ sqrMod.pm = &m;
+ zz = 1;
+ mcl::fp::powGeneric(zz, x, &y.buf_[0], y.size(), mulMod, sqrMod, (void (*)(VintT&, const VintT&))0);
+ z.swap(zz);
+ }
+ /*
+ inverse mod
+ y = 1/x mod m
+ REMARK x != 0 and m != 0;
+ */
+ static void invMod(VintT& y, const VintT& x, const VintT& m)
+ {
+ assert(!x.isZero() && !m.isZero());
+ if (x == 1) {
+ y = 1;
+ return;
+ }
+ VintT a = 1;
+ VintT t;
+ VintT q;
+ divMod(&q, t, m, x);
+ VintT s = x;
+ VintT b = -q;
+
+ for (;;) {
+ divMod(&q, s, s, t);
+ if (s.isZero()) {
+ if (b.isNeg_) {
+ b += m;
+ }
+ y = b;
+ return;
+ }
+ a -= b * q;
+
+ divMod(&q, t, t, s);
+ if (t.isZero()) {
+ if (a.isNeg_) {
+ a += m;
+ }
+ y = a;
+ return;
+ }
+ b -= a * q;
+ }
+ }
+ /*
+ Miller-Rabin
+ */
+ static bool isPrime(bool *pb, const VintT& n, int tryNum = 32)
+ {
+ *pb = true;
+ if (n <= 1) return false;
+ if (n == 2 || n == 3) return true;
+ if (n.isEven()) return false;
+ cybozu::XorShift rg;
+ const VintT nm1 = n - 1;
+ VintT d = nm1;
+ uint32_t r = countTrailingZero(d);
+ // n - 1 = 2^r d
+ VintT a, x;
+ for (int i = 0; i < tryNum; i++) {
+ a.setRand(pb, n - 3, rg);
+ if (!*pb) return false;
+ a += 2; // a in [2, n - 2]
+ powMod(x, a, d, n);
+ if (x == 1 || x == nm1) {
+ continue;
+ }
+ for (uint32_t j = 1; j < r; j++) {
+ sqr(x, x);
+ x %= n;
+ if (x == 1) return false;
+ if (x == nm1) goto NEXT_LOOP;
+ }
+ return false;
+ NEXT_LOOP:;
+ }
+ return true;
+ }
+ bool isPrime(bool *pb, int tryNum = 32) const
+ {
+ return isPrime(pb, *this, tryNum);
+ }
+ static void gcd(VintT& z, VintT x, VintT y)
+ {
+ VintT t;
+ for (;;) {
+ if (y.isZero()) {
+ z = x;
+ return;
+ }
+ t = x;
+ x = y;
+ mod(y, t, y);
+ }
+ }
+ static VintT gcd(const VintT& x, const VintT& y)
+ {
+ VintT z;
+ gcd(z, x, y);
+ return z;
+ }
+ static void lcm(VintT& z, const VintT& x, const VintT& y)
+ {
+ VintT c;
+ gcd(c, x, y);
+ div(c, x, c);
+ mul(z, c, y);
+ }
+ static VintT lcm(const VintT& x, const VintT& y)
+ {
+ VintT z;
+ lcm(z, x, y);
+ return z;
+ }
+ /*
+ 1 if m is quadratic residue modulo n (i.e., there exists an x s.t. x^2 = m mod n)
+ 0 if m = 0 mod n
+ -1 otherwise
+ @note return legendre_symbol(m, p) for m and odd prime p
+ */
+ static int jacobi(VintT m, VintT n)
+ {
+ assert(n.isOdd());
+ if (n == 1) return 1;
+ if (m < 0 || m > n) {
+ quotRem(0, m, m, n); // m = m mod n
+ }
+ if (m.isZero()) return 0;
+ if (m == 1) return 1;
+ if (gcd(m, n) != 1) return 0;
+
+ int j = 1;
+ VintT t;
+ goto START;
+ while (m != 1) {
+ if ((m.getLow32bit() % 4) == 3 && (n.getLow32bit() % 4) == 3) {
+ j = -j;
+ }
+ mod(t, n, m);
+ n = m;
+ m = t;
+ START:
+ int s = countTrailingZero(m);
+ uint32_t nmod8 = n.getLow32bit() % 8;
+ if ((s % 2) && (nmod8 == 3 || nmod8 == 5)) {
+ j = -j;
+ }
+ }
+ return j;
+ }
+#ifndef CYBOZU_DONT_USE_STRING
+ explicit VintT(const std::string& str)
+ : size_(0)
+ {
+ setStr(str);
+ }
+ void getStr(std::string& s, int base = 10) const
+ {
+ s.clear();
+ cybozu::StringOutputStream os(s);
+ save(os, base);
+ }
+ std::string getStr(int base = 10) const
+ {
+ std::string s;
+ getStr(s, base);
+ return s;
+ }
+ inline friend std::ostream& operator<<(std::ostream& os, const VintT& x)
+ {
+ return os << x.getStr(os.flags() & std::ios_base::hex ? 16 : 10);
+ }
+ inline friend std::istream& operator>>(std::istream& is, VintT& x)
+ {
+ x.load(is);
+ return is;
+ }
+#endif
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ void setStr(const std::string& str, int base = 0)
+ {
+ bool b;
+ setStr(&b, str.c_str(), base);
+ if (!b) throw cybozu::Exception("Vint:setStr") << str;
+ }
+ void setRand(const VintT& max, fp::RandGen rg = fp::RandGen())
+ {
+ bool b;
+ setRand(&b, max, rg);
+ if (!b) throw cybozu::Exception("Vint:setRand");
+ }
+ void getArray(Unit *x, size_t maxSize) const
+ {
+ bool b;
+ getArray(&b, x, maxSize);
+ if (!b) throw cybozu::Exception("Vint:getArray");
+ }
+ template<class InputStream>
+ void load(InputStream& is, int ioMode = 0)
+ {
+ bool b;
+ load(&b, is, ioMode);
+ if (!b) throw cybozu::Exception("Vint:load");
+ }
+ template<class OutputStream>
+ void save(OutputStream& os, int base = 10) const
+ {
+ bool b;
+ save(&b, os, base);
+ if (!b) throw cybozu::Exception("Vint:save");
+ }
+ static bool isPrime(const VintT& n, int tryNum = 32)
+ {
+ bool b;
+ bool ret = isPrime(&b, n, tryNum);
+ if (!b) throw cybozu::Exception("Vint:isPrime");
+ return ret;
+ }
+ bool isPrime(int tryNum = 32) const
+ {
+ bool b;
+ bool ret = isPrime(&b, *this, tryNum);
+ if (!b) throw cybozu::Exception("Vint:isPrime");
+ return ret;
+ }
+ template<class S>
+ void setArray(const S *x, size_t size)
+ {
+ bool b;
+ setArray(&b, x, size);
+ if (!b) throw cybozu::Exception("Vint:setArray");
+ }
+#endif
+ VintT& operator++() { adds1(*this, *this, 1); return *this; }
+ VintT& operator--() { subs1(*this, *this, 1); return *this; }
+ VintT operator++(int) { VintT c = *this; adds1(*this, *this, 1); return c; }
+ VintT operator--(int) { VintT c = *this; subs1(*this, *this, 1); return c; }
+ friend bool operator<(const VintT& x, const VintT& y) { return compare(x, y) < 0; }
+ friend bool operator>=(const VintT& x, const VintT& y) { return !operator<(x, y); }
+ friend bool operator>(const VintT& x, const VintT& y) { return compare(x, y) > 0; }
+ friend bool operator<=(const VintT& x, const VintT& y) { return !operator>(x, y); }
+ friend bool operator==(const VintT& x, const VintT& y) { return compare(x, y) == 0; }
+ friend bool operator!=(const VintT& x, const VintT& y) { return !operator==(x, y); }
+
+ friend bool operator<(const VintT& x, int y) { return compares1(x, y) < 0; }
+ friend bool operator>=(const VintT& x, int y) { return !operator<(x, y); }
+ friend bool operator>(const VintT& x, int y) { return compares1(x, y) > 0; }
+ friend bool operator<=(const VintT& x, int y) { return !operator>(x, y); }
+ friend bool operator==(const VintT& x, int y) { return compares1(x, y) == 0; }
+ friend bool operator!=(const VintT& x, int y) { return !operator==(x, y); }
+
+ friend bool operator<(const VintT& x, uint32_t y) { return compareu1(x, y) < 0; }
+ friend bool operator>=(const VintT& x, uint32_t y) { return !operator<(x, y); }
+ friend bool operator>(const VintT& x, uint32_t y) { return compareu1(x, y) > 0; }
+ friend bool operator<=(const VintT& x, uint32_t y) { return !operator>(x, y); }
+ friend bool operator==(const VintT& x, uint32_t y) { return compareu1(x, y) == 0; }
+ friend bool operator!=(const VintT& x, uint32_t y) { return !operator==(x, y); }
+
+ VintT& operator+=(const VintT& rhs) { add(*this, *this, rhs); return *this; }
+ VintT& operator-=(const VintT& rhs) { sub(*this, *this, rhs); return *this; }
+ VintT& operator*=(const VintT& rhs) { mul(*this, *this, rhs); return *this; }
+ VintT& operator/=(const VintT& rhs) { div(*this, *this, rhs); return *this; }
+ VintT& operator%=(const VintT& rhs) { mod(*this, *this, rhs); return *this; }
+ VintT& operator&=(const VintT& rhs) { andBit(*this, *this, rhs); return *this; }
+ VintT& operator|=(const VintT& rhs) { orBit(*this, *this, rhs); return *this; }
+
+ VintT& operator+=(int rhs) { adds1(*this, *this, rhs); return *this; }
+ VintT& operator-=(int rhs) { subs1(*this, *this, rhs); return *this; }
+ VintT& operator*=(int rhs) { muls1(*this, *this, rhs); return *this; }
+ VintT& operator/=(int rhs) { divs1(*this, *this, rhs); return *this; }
+ VintT& operator%=(int rhs) { mods1(*this, *this, rhs); return *this; }
+ VintT& operator+=(Unit rhs) { addu1(*this, *this, rhs); return *this; }
+ VintT& operator-=(Unit rhs) { subu1(*this, *this, rhs); return *this; }
+ VintT& operator*=(Unit rhs) { mulu1(*this, *this, rhs); return *this; }
+ VintT& operator/=(Unit rhs) { divu1(*this, *this, rhs); return *this; }
+ VintT& operator%=(Unit rhs) { modu1(*this, *this, rhs); return *this; }
+
+ VintT& operator&=(Unit rhs) { andBitu1(*this, *this, rhs); return *this; }
+ VintT& operator|=(Unit rhs) { orBitu1(*this, *this, rhs); return *this; }
+
+ friend VintT operator+(const VintT& a, const VintT& b) { VintT c; add(c, a, b); return c; }
+ friend VintT operator-(const VintT& a, const VintT& b) { VintT c; sub(c, a, b); return c; }
+ friend VintT operator*(const VintT& a, const VintT& b) { VintT c; mul(c, a, b); return c; }
+ friend VintT operator/(const VintT& a, const VintT& b) { VintT c; div(c, a, b); return c; }
+ friend VintT operator%(const VintT& a, const VintT& b) { VintT c; mod(c, a, b); return c; }
+ friend VintT operator&(const VintT& a, const VintT& b) { VintT c; andBit(c, a, b); return c; }
+ friend VintT operator|(const VintT& a, const VintT& b) { VintT c; orBit(c, a, b); return c; }
+
+ friend VintT operator+(const VintT& a, int b) { VintT c; adds1(c, a, b); return c; }
+ friend VintT operator-(const VintT& a, int b) { VintT c; subs1(c, a, b); return c; }
+ friend VintT operator*(const VintT& a, int b) { VintT c; muls1(c, a, b); return c; }
+ friend VintT operator/(const VintT& a, int b) { VintT c; divs1(c, a, b); return c; }
+ friend VintT operator%(const VintT& a, int b) { VintT c; mods1(c, a, b); return c; }
+ friend VintT operator+(const VintT& a, Unit b) { VintT c; addu1(c, a, b); return c; }
+ friend VintT operator-(const VintT& a, Unit b) { VintT c; subu1(c, a, b); return c; }
+ friend VintT operator*(const VintT& a, Unit b) { VintT c; mulu1(c, a, b); return c; }
+ friend VintT operator/(const VintT& a, Unit b) { VintT c; divu1(c, a, b); return c; }
+ friend VintT operator%(const VintT& a, Unit b) { VintT c; modu1(c, a, b); return c; }
+
+ friend VintT operator&(const VintT& a, Unit b) { VintT c; andBitu1(c, a, b); return c; }
+ friend VintT operator|(const VintT& a, Unit b) { VintT c; orBitu1(c, a, b); return c; }
+
+ VintT operator-() const { VintT c; neg(c, *this); return c; }
+ VintT& operator<<=(size_t n) { shl(*this, *this, n); return *this; }
+ VintT& operator>>=(size_t n) { shr(*this, *this, n); return *this; }
+ VintT operator<<(size_t n) const { VintT c = *this; c <<= n; return c; }
+ VintT operator>>(size_t n) const { VintT c = *this; c >>= n; return c; }
+};
+
+#ifdef MCL_VINT_FIXED_BUFFER
+typedef VintT<vint::FixedBuffer<mcl::vint::Unit, MCL_MAX_BIT_SIZE * 2> > Vint;
+#else
+typedef VintT<vint::Buffer<mcl::vint::Unit> > Vint;
+#endif
+
+} // mcl
+
+//typedef mcl::Vint mpz_class;
diff --git a/vendor/github.com/byzantine-lab/mcl/include/mcl/window_method.hpp b/vendor/github.com/byzantine-lab/mcl/include/mcl/window_method.hpp
new file mode 100644
index 000000000..cb4fad37e
--- /dev/null
+++ b/vendor/github.com/byzantine-lab/mcl/include/mcl/window_method.hpp
@@ -0,0 +1,175 @@
+#pragma once
+/**
+ @file
+ @brief window method
+ @author MITSUNARI Shigeo(@herumi)
+*/
+#include <mcl/array.hpp>
+#include <mcl/fp.hpp>
+
+namespace mcl { namespace fp {
+
+/*
+ get w-bit size from x[0, bitSize)
+ @param x [in] data
+ @param bitSize [in] data size
+ @param w [in] split size < UnitBitSize
+*/
+template<class T>
+struct ArrayIterator {
+ static const size_t TbitSize = sizeof(T) * 8;
+ ArrayIterator(const T *x, size_t bitSize, size_t w)
+ : x(x)
+ , bitSize(bitSize)
+ , w(w)
+ , pos(0)
+ , mask((w == TbitSize ? 0 : (T(1) << w)) - 1)
+ {
+ assert(w <= TbitSize);
+ }
+ bool hasNext() const { return bitSize > 0; }
+ T getNext()
+ {
+ if (w == TbitSize) {
+ bitSize -= w;
+ return *x++;
+ }
+ if (pos + w < TbitSize) {
+ T v = (*x >> pos) & mask;
+ pos += w;
+ if (bitSize < w) {
+ bitSize = 0;
+ } else {
+ bitSize -= w;
+ }
+ return v;
+ }
+ if (pos + bitSize <= TbitSize) {
+ assert(bitSize <= w);
+ T v = *x >> pos;
+ assert((v >> bitSize) == 0);
+ bitSize = 0;
+ return v & mask;
+ }
+ assert(pos > 0);
+ T v = (x[0] >> pos) | (x[1] << (TbitSize - pos));
+ v &= mask;
+ pos = (pos + w) - TbitSize;
+ bitSize -= w;
+ x++;
+ return v;
+ }
+ const T *x;
+ size_t bitSize;
+ size_t w;
+ size_t pos;
+ T mask;
+};
+
+template<class Ec>
+class WindowMethod {
+public:
+ size_t bitSize_;
+ size_t winSize_;
+ mcl::Array<Ec> tbl_;
+ WindowMethod(const Ec& x, size_t bitSize, size_t winSize)
+ {
+ init(x, bitSize, winSize);
+ }
+ WindowMethod()
+ : bitSize_(0)
+ , winSize_(0)
+ {
+ }
+ /*
+ @param x [in] base index
+ @param bitSize [in] exponent bit length
+ @param winSize [in] window size
+ */
+ void init(bool *pb, const Ec& x, size_t bitSize, size_t winSize)
+ {
+ bitSize_ = bitSize;
+ winSize_ = winSize;
+ const size_t tblNum = (bitSize + winSize - 1) / winSize;
+ const size_t r = size_t(1) << winSize;
+ *pb = tbl_.resize(tblNum * r);
+ if (!*pb) return;
+ Ec t(x);
+ for (size_t i = 0; i < tblNum; i++) {
+ Ec* w = &tbl_[i * r];
+ w[0].clear();
+ for (size_t d = 1; d < r; d *= 2) {
+ for (size_t j = 0; j < d; j++) {
+ Ec::add(w[j + d], w[j], t);
+ }
+ Ec::dbl(t, t);
+ }
+ for (size_t j = 0; j < r; j++) {
+ w[j].normalize();
+ }
+ }
+ }
+#ifndef CYBOZU_DONT_USE_EXCEPTION
+ void init(const Ec& x, size_t bitSize, size_t winSize)
+ {
+ bool b;
+ init(&b, x, bitSize, winSize);
+ if (!b) throw cybozu::Exception("mcl:WindowMethod:init") << bitSize << winSize;
+ }
+#endif
+ /*
+ @param z [out] x multiplied by y
+ @param y [in] exponent
+ */
+ template<class tag2, size_t maxBitSize2>
+ void mul(Ec& z, const FpT<tag2, maxBitSize2>& y) const
+ {
+ fp::Block b;
+ y.getBlock(b);
+ powArray(z, b.p, b.n, false);
+ }
+ void mul(Ec& z, int64_t y) const
+ {
+#if MCL_SIZEOF_UNIT == 8
+ Unit u = fp::abs_(y);
+ powArray(z, &u, 1, y < 0);
+#else
+ uint64_t ua = fp::abs_(y);
+ Unit u[2] = { uint32_t(ua), uint32_t(ua >> 32) };
+ size_t un = u[1] ? 2 : 1;
+ powArray(z, u, un, y < 0);
+#endif
+ }
+ void mul(Ec& z, const mpz_class& y) const
+ {
+ powArray(z, gmp::getUnit(y), gmp::getUnitSize(y), y < 0);
+ }
+ void powArray(Ec& z, const Unit* y, size_t n, bool isNegative) const
+ {
+ z.clear();
+ while (n > 0) {
+ if (y[n - 1]) break;
+ n--;
+ }
+ if (n == 0) return;
+ assert((n << winSize_) <= tbl_.size());
+ if ((n << winSize_) > tbl_.size()) return;
+ assert(y[n - 1]);
+ const size_t bitSize = (n - 1) * UnitBitSize + cybozu::bsr<Unit>(y[n - 1]) + 1;
+ size_t i = 0;
+ ArrayIterator<Unit> ai(y, bitSize, winSize_);
+ do {
+ Unit v = ai.getNext();
+ if (v) {
+ Ec::add(z, z, tbl_[(i << winSize_) + v]);
+ }
+ i++;
+ } while (ai.hasNext());
+ if (isNegative) {
+ Ec::neg(z, z);
+ }
+ }
+};
+
+} } // mcl::fp
+