diff options
Diffstat (limited to 'vendor/github.com/byzantine-lab/mcl/include/mcl')
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 + |