diff options
Diffstat (limited to 'vendor/github.com/dexon-foundation/mcl/include')
52 files changed, 18982 insertions, 0 deletions
diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/array.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/array.hpp new file mode 100644 index 000000000..30df3667d --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/array.hpp @@ -0,0 +1,197 @@ +#pragma once + +/** + @file + @brief scoped array and aligned array + + @author MITSUNARI Shigeo(@herumi) +*/ +#include <new> +#include <utility> +#ifdef _WIN32 + #include <malloc.h> +#else + #include <stdlib.h> +#endif +#include <cybozu/inttype.hpp> + +namespace cybozu { + +inline void *AlignedMalloc(size_t size, size_t alignment) +{ +#ifdef _WIN32 + return _aligned_malloc(size, alignment); +#else + void *p; + int ret = posix_memalign(&p, alignment, size); + return (ret == 0) ? p : 0; +#endif +} + +inline void AlignedFree(void *p) +{ +#ifdef _WIN32 + if (p == 0) return; + _aligned_free(p); +#else + free(p); +#endif +} + +template<class T> +class ScopedArray { + T *p_; + size_t size_; + ScopedArray(const ScopedArray&); + void operator=(const ScopedArray&); +public: + explicit ScopedArray(size_t size) + : p_(new T[size]) + , size_(size) + { + } + ~ScopedArray() + { + delete[] p_; + } + T& operator[](size_t idx) CYBOZU_NOEXCEPT { return p_[idx]; } + const T& operator[](size_t idx) const CYBOZU_NOEXCEPT { return p_[idx]; } + size_t size() const CYBOZU_NOEXCEPT { return size_; } + bool empty() const CYBOZU_NOEXCEPT { return size_ == 0; } + T* begin() CYBOZU_NOEXCEPT { return p_; } + T* end() CYBOZU_NOEXCEPT { return p_ + size_; } + const T* begin() const CYBOZU_NOEXCEPT { return p_; } + const T* end() const CYBOZU_NOEXCEPT { return p_ + size_; } + T* data() CYBOZU_NOEXCEPT { return p_; } + const T* data() const CYBOZU_NOEXCEPT { return p_; } +}; + +/** + T must be POD type + 16byte aligment array +*/ +template<class T, size_t N = 16, bool defaultDoClear = true> +class AlignedArray { + T *p_; + size_t size_; + size_t allocSize_; + T *alloc(size_t size) const + { + T *p = static_cast<T*>(AlignedMalloc(size * sizeof(T), N)); + if (p == 0) throw std::bad_alloc(); + return p; + } + void copy(T *dst, const T *src, size_t n) const + { + for (size_t i = 0; i < n; i++) dst[i] = src[i]; + } + void setZero(T *p, size_t n) const + { + for (size_t i = 0; i < n; i++) p[i] = 0; + } + /* + alloc allocN and copy [p, p + copyN) to new p_ + don't modify size_ + */ + void allocCopy(size_t allocN, const T *p, size_t copyN) + { + T *q = alloc(allocN); + copy(q, p, copyN); + AlignedFree(p_); + p_ = q; + allocSize_ = allocN; + } +public: + /* + don't clear buffer with zero if doClear is false + */ + explicit AlignedArray(size_t size = 0, bool doClear = defaultDoClear) + : p_(0) + , size_(0) + , allocSize_(0) + { + resize(size, doClear); + } + AlignedArray(const AlignedArray& rhs) + : p_(0) + , size_(0) + , allocSize_(0) + { + *this = rhs; + } + AlignedArray& operator=(const AlignedArray& rhs) + { + if (allocSize_ < rhs.size_) { + allocCopy(rhs.size_, rhs.p_, rhs.size_); + } else { + copy(p_, rhs.p_, rhs.size_); + } + size_ = rhs.size_; + return *this; + } +#if (CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11) + AlignedArray(AlignedArray&& rhs) CYBOZU_NOEXCEPT + : p_(rhs.p_) + , size_(rhs.size_) + , allocSize_(rhs.allocSize_) + { + rhs.p_ = 0; + rhs.size_ = 0; + rhs.allocSize_ = 0; + } + AlignedArray& operator=(AlignedArray&& rhs) CYBOZU_NOEXCEPT + { + swap(rhs); + rhs.clear(); + return *this; + } +#endif + /* + don't clear buffer with zero if doClear is false + @note don't free if shrinked + */ + void resize(size_t size, bool doClear = defaultDoClear) + { + // shrink + if (size <= size_) { + size_ = size; + return; + } + // realloc if necessary + if (size > allocSize_) { + allocCopy(size, p_, size_); + } + if (doClear) setZero(p_ + size_, size - size_); + size_ = size; + } + void clear() // not free + { + size_ = 0; + } + ~AlignedArray() + { + AlignedFree(p_); + } + void swap(AlignedArray& rhs) CYBOZU_NOEXCEPT + { + std::swap(p_, rhs.p_); + std::swap(size_, rhs.size_); + std::swap(allocSize_, rhs.allocSize_); + } + T& operator[](size_t idx) CYBOZU_NOEXCEPT { return p_[idx]; } + const T& operator[](size_t idx) const CYBOZU_NOEXCEPT { return p_[idx]; } + size_t size() const CYBOZU_NOEXCEPT { return size_; } + bool empty() const CYBOZU_NOEXCEPT { return size_ == 0; } + T* begin() CYBOZU_NOEXCEPT { return p_; } + T* end() CYBOZU_NOEXCEPT { return p_ + size_; } + const T* begin() const CYBOZU_NOEXCEPT { return p_; } + const T* end() const CYBOZU_NOEXCEPT { return p_ + size_; } + T* data() CYBOZU_NOEXCEPT { return p_; } + const T* data() const CYBOZU_NOEXCEPT { return p_; } +#if (CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11) + const T* cbegin() const CYBOZU_NOEXCEPT { return p_; } + const T* cend() const CYBOZU_NOEXCEPT { return p_ + size_; } +#endif +}; + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/atoi.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/atoi.hpp new file mode 100644 index 000000000..a22853a17 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/atoi.hpp @@ -0,0 +1,239 @@ +#pragma once +/** + @file + @brief converter between integer and string + + @author MITSUNARI Shigeo(@herumi) +*/ + +#include <memory.h> +#include <limits.h> +#include <limits> +#include <cybozu/exception.hpp> + +namespace cybozu { + +namespace atoi_local { + +template<typename T, size_t n> +T convertToInt(bool *b, const char *p, size_t size, const char (&max)[n], T min, T overflow1, char overflow2) +{ + if (size > 0 && *p) { + bool isMinus = false; + size_t i = 0; + if (*p == '-') { + isMinus = true; + i++; + } + if (i < size && p[i]) { + // skip leading zero + while (i < size && p[i] == '0') i++; + // check minimum + if (isMinus && size - i >= n - 1 && memcmp(max, &p[i], n - 1) == 0) { + if (b) *b = true; + return min; + } + T x = 0; + for (;;) { + unsigned char c; + if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') { + if (b) *b = true; + return isMinus ? -x : x; + } + unsigned int y = c - '0'; + if (y > 9 || x > overflow1 || (x == overflow1 && c >= overflow2)) { + break; + } + x = x * 10 + T(y); + i++; + } + } + } + if (b) { + *b = false; + return 0; + } else { + throw cybozu::Exception("atoi::convertToInt") << cybozu::exception::makeString(p, size); + } +} + +template<typename T> +T convertToUint(bool *b, const char *p, size_t size, T overflow1, char overflow2) +{ + if (size > 0 && *p) { + size_t i = 0; + // skip leading zero + while (i < size && p[i] == '0') i++; + T x = 0; + for (;;) { + unsigned char c; + if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') { + if (b) *b = true; + return x; + } + unsigned int y = c - '0'; + if (y > 9 || x > overflow1 || (x == overflow1 && c >= overflow2)) { + break; + } + x = x * 10 + T(y); + i++; + } + } + if (b) { + *b = false; + return 0; + } else { + throw cybozu::Exception("atoi::convertToUint") << cybozu::exception::makeString(p, size); + } +} + +template<typename T> +T convertHexToInt(bool *b, const char *p, size_t size) +{ + if (size > 0 && *p) { + size_t i = 0; + T x = 0; + for (;;) { + unsigned int c; + if (i == size || (c = static_cast<unsigned char>(p[i])) == '\0') { + if (b) *b = true; + return x; + } + if (c - 'A' <= 'F' - 'A') { + c = (c - 'A') + 10; + } else if (c - 'a' <= 'f' - 'a') { + c = (c - 'a') + 10; + } else if (c - '0' <= '9' - '0') { + c = c - '0'; + } else { + break; + } + // avoid overflow + if (x > (std::numeric_limits<T>::max)() / 16) break; + x = x * 16 + T(c); + i++; + } + } + if (b) { + *b = false; + return 0; + } else { + throw cybozu::Exception("atoi::convertHexToInt") << cybozu::exception::makeString(p, size); + } +} + +} // atoi_local + +/** + auto detect return value class + @note if you set bool pointer p then throw nothing and set *p = false if bad string +*/ +class atoi { + const char *p_; + size_t size_; + bool *b_; + void set(bool *b, const char *p, size_t size) + { + b_ = b; + p_ = p; + size_ = size; + } +public: + atoi(const char *p, size_t size = -1) + { + set(0, p, size); + } + atoi(bool *b, const char *p, size_t size = -1) + { + set(b, p, size); + } + atoi(const std::string& str) + { + set(0, str.c_str(), str.size()); + } + atoi(bool *b, const std::string& str) + { + set(b, str.c_str(), str.size()); + } + inline operator signed char() const + { + return atoi_local::convertToInt<signed char>(b_, p_, size_, "128", -128, 12, '8'); + } + inline operator unsigned char() const + { + return atoi_local::convertToUint<unsigned char>(b_, p_, size_, 25, '6'); + } + inline operator short() const + { + return atoi_local::convertToInt<short>(b_, p_, size_, "32768", -32768, 3276, '8'); + } + inline operator unsigned short() const + { + return atoi_local::convertToUint<unsigned short>(b_, p_, size_, 6553, '6'); + } + inline operator int() const + { + return atoi_local::convertToInt<int>(b_, p_, size_, "2147483648", INT_MIN, 214748364, '8'); + } + inline operator unsigned int() const + { + return atoi_local::convertToUint<unsigned int>(b_, p_, size_, 429496729, '6'); + } + inline operator long long() const + { + return atoi_local::convertToInt<long long>(b_, p_, size_, "9223372036854775808", LLONG_MIN, 922337203685477580LL, '8'); + } + inline operator unsigned long long() const + { + return atoi_local::convertToUint<unsigned long long>(b_, p_, size_, 1844674407370955161ULL, '6'); + } +#if defined(__SIZEOF_LONG__) && (__SIZEOF_LONG__ == 8) + inline operator long() const { return static_cast<long>(static_cast<long long>(*this)); } + inline operator unsigned long() const { return static_cast<unsigned long>(static_cast<unsigned long long>(*this)); } +#else + inline operator long() const { return static_cast<long>(static_cast<int>(*this)); } + inline operator unsigned long() const { return static_cast<unsigned long>(static_cast<unsigned int>(*this)); } +#endif +}; + +class hextoi { + const char *p_; + size_t size_; + bool *b_; + void set(bool *b, const char *p, size_t size) + { + b_ = b; + p_ = p; + size_ = size; + } +public: + hextoi(const char *p, size_t size = -1) + { + set(0, p, size); + } + hextoi(bool *b, const char *p, size_t size = -1) + { + set(b, p, size); + } + hextoi(const std::string& str) + { + set(0, str.c_str(), str.size()); + } + hextoi(bool *b, const std::string& str) + { + set(b, str.c_str(), str.size()); + } + operator unsigned char() const { return atoi_local::convertHexToInt<unsigned char>(b_, p_, size_); } + operator unsigned short() const { return atoi_local::convertHexToInt<unsigned short>(b_, p_, size_); } + operator unsigned int() const { return atoi_local::convertHexToInt<unsigned int>(b_, p_, size_); } + operator unsigned long() const { return atoi_local::convertHexToInt<unsigned long>(b_, p_, size_); } + operator unsigned long long() const { return atoi_local::convertHexToInt<unsigned long long>(b_, p_, size_); } + operator char() const { return atoi_local::convertHexToInt<char>(b_, p_, size_); } + operator signed char() const { return atoi_local::convertHexToInt<signed char>(b_, p_, size_); } + operator short() const { return atoi_local::convertHexToInt<short>(b_, p_, size_); } + operator int() const { return atoi_local::convertHexToInt<int>(b_, p_, size_); } + operator long() const { return atoi_local::convertHexToInt<long>(b_, p_, size_); } + operator long long() const { return atoi_local::convertHexToInt<long long>(b_, p_, size_); } +}; + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/benchmark.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/benchmark.hpp new file mode 100644 index 000000000..4c02f1869 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/benchmark.hpp @@ -0,0 +1,212 @@ +#pragma once +/** + @file + @brief measure exec time of function + @author MITSUNARI Shigeo +*/ +#if defined(_MSC_VER) && (MSC_VER <= 1500) + #include <cybozu/inttype.hpp> +#else + #include <stdint.h> +#endif +#include <stdio.h> + +#ifdef __EMSCRIPTEN__ + #define CYBOZU_BENCH_USE_GETTIMEOFDAY +#endif + +#ifdef CYBOZU_BENCH_USE_GETTIMEOFDAY + #include <sys/time.h> +#elif !defined(CYBOZU_BENCH_DONT_USE_RDTSC) + #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) + #define CYBOZU_BENCH_USE_RDTSC + #define CYBOZU_BENCH_USE_CPU_TIMER + #endif + #if defined(__GNUC__) && defined(__ARM_ARCH_7A__) +// #define CYBOZU_BENCH_USE_MRC +// #define CYBOZU_BENCH_USE_CPU_TIMER + #endif +#endif + + +#include <assert.h> +#include <time.h> +#ifdef _MSC_VER + #include <intrin.h> + #include <sys/timeb.h> +#else +#endif + +#ifndef CYBOZU_UNUSED + #ifdef __GNUC__ + #define CYBOZU_UNUSED __attribute__((unused)) + #else + #define CYBOZU_UNUSED + #endif +#endif + +namespace cybozu { + +namespace bench { + +static void (*g_putCallback)(double); + +static inline void setPutCallback(void (*f)(double)) +{ + g_putCallback = f; +} + +} // cybozu::bench + +class CpuClock { +public: + static inline uint64_t getCpuClk() + { +#ifdef CYBOZU_BENCH_USE_RDTSC +#ifdef _MSC_VER + return __rdtsc(); +#else + unsigned int eax, edx; + __asm__ volatile("rdtsc" : "=a"(eax), "=d"(edx)); + return ((uint64_t)edx << 32) | eax; +#endif +#elif defined(CYBOZU_BENCH_USE_MRC) + uint32_t clk; + __asm__ volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(clk)); + return clk; +#else +#ifdef _MSC_VER + struct _timeb timeb; + _ftime_s(&timeb); + return uint64_t(timeb.time) * 1000000000 + timeb.millitm * 1000000; +#elif defined(CYBOZU_BENCH_USE_GETTIMEOFDAY) + struct timeval tv; + int ret CYBOZU_UNUSED = gettimeofday(&tv, 0); + assert(ret == 0); + return uint64_t(tv.tv_sec) * 1000000000 + tv.tv_usec * 1000; +#else + struct timespec tp; + int ret CYBOZU_UNUSED = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); + assert(ret == 0); + return uint64_t(tp.tv_sec) * 1000000000 + tp.tv_nsec; +#endif +#endif + } + CpuClock() + : clock_(0) + , count_(0) + { + } + void begin() + { + clock_ -= getCpuClk(); + } + void end() + { + clock_ += getCpuClk(); + count_++; + } + int getCount() const { return count_; } + uint64_t getClock() const { return clock_; } + void clear() { count_ = 0; clock_ = 0; } + void put(const char *msg = 0, int N = 1) const + { + double t = getClock() / double(getCount()) / N; + if (msg && *msg) printf("%s ", msg); + if (bench::g_putCallback) { + bench::g_putCallback(t); + return; + } +#ifdef CYBOZU_BENCH_USE_CPU_TIMER + if (t > 1e6) { + printf("%7.3fMclk", t * 1e-6); + } else if (t > 1e3) { + printf("%7.3fKclk", t * 1e-3); + } else { + printf("%6.2f clk", t); + } +#else + if (t > 1e6) { + printf("%7.3fmsec", t * 1e-6); + } else if (t > 1e3) { + printf("%7.3fusec", t * 1e-3); + } else { + printf("%6.2fnsec", t); + } +#endif + if (msg && *msg) printf("\n"); + } + // adhoc constatns for CYBOZU_BENCH +#ifdef CYBOZU_BENCH_USE_CPU_TIMER + static const int loopN1 = 1000; + static const int loopN2 = 100; + static const uint64_t maxClk = (uint64_t)1e8; +#else + static const int loopN1 = 100; + static const int loopN2 = 100; + static const uint64_t maxClk = (uint64_t)1e8; +#endif +private: + uint64_t clock_; + int count_; +}; + +namespace bench { + +static CpuClock g_clk; +static int CYBOZU_UNUSED g_loopNum; + +} // cybozu::bench +/* + loop counter is automatically determined + CYBOZU_BENCH(<msg>, <func>, <param1>, <param2>, ...); + if msg == "" then only set g_clk, g_loopNum +*/ +#define CYBOZU_BENCH(msg, func, ...) \ +{ \ + const uint64_t _cybozu_maxClk = cybozu::CpuClock::maxClk; \ + cybozu::CpuClock _cybozu_clk; \ + for (int _cybozu_i = 0; _cybozu_i < cybozu::CpuClock::loopN2; _cybozu_i++) { \ + _cybozu_clk.begin(); \ + for (int _cybozu_j = 0; _cybozu_j < cybozu::CpuClock::loopN1; _cybozu_j++) { func(__VA_ARGS__); } \ + _cybozu_clk.end(); \ + if (_cybozu_clk.getClock() > _cybozu_maxClk) break; \ + } \ + if (msg && *msg) _cybozu_clk.put(msg, cybozu::CpuClock::loopN1); \ + cybozu::bench::g_clk = _cybozu_clk; cybozu::bench::g_loopNum = cybozu::CpuClock::loopN1; \ +} + +/* + double clk; + CYBOZU_BENCH_T(clk, <func>, <param1>, <param2>, ...); + clk is set by CYBOZU_BENCH_T +*/ +#define CYBOZU_BENCH_T(clk, func, ...) \ +{ \ + const uint64_t _cybozu_maxClk = cybozu::CpuClock::maxClk; \ + cybozu::CpuClock _cybozu_clk; \ + for (int _cybozu_i = 0; _cybozu_i < cybozu::CpuClock::loopN2; _cybozu_i++) { \ + _cybozu_clk.begin(); \ + for (int _cybozu_j = 0; _cybozu_j < cybozu::CpuClock::loopN1; _cybozu_j++) { func(__VA_ARGS__); } \ + _cybozu_clk.end(); \ + if (_cybozu_clk.getClock() > _cybozu_maxClk) break; \ + } \ + clk = _cybozu_clk.getClock() / (double)_cybozu_clk.getCount() / cybozu::CpuClock::loopN1; \ +} + +/* + loop counter N is given + CYBOZU_BENCH_C(<msg>, <counter>, <func>, <param1>, <param2>, ...); + if msg == "" then only set g_clk, g_loopNum +*/ +#define CYBOZU_BENCH_C(msg, _N, func, ...) \ +{ \ + cybozu::CpuClock _cybozu_clk; \ + _cybozu_clk.begin(); \ + for (int _cybozu_j = 0; _cybozu_j < _N; _cybozu_j++) { func(__VA_ARGS__); } \ + _cybozu_clk.end(); \ + if (msg && *msg) _cybozu_clk.put(msg, _N); \ + cybozu::bench::g_clk = _cybozu_clk; cybozu::bench::g_loopNum = _N; \ +} + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/bit_operation.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/bit_operation.hpp new file mode 100644 index 000000000..865c1e47d --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/bit_operation.hpp @@ -0,0 +1,139 @@ +#pragma once +/** + @file + @brief bit operation +*/ +#include <assert.h> +#include <cybozu/inttype.hpp> + +#if (CYBOZU_HOST == CYBOZU_HOST_INTEL) + #if defined(_WIN32) + #include <intrin.h> + #elif defined(__linux__) || defined(__CYGWIN__) || defined(__clang__) + #include <x86intrin.h> + #elif defined(__GNUC__) + #include <emmintrin.h> + #endif +#endif + +namespace cybozu { + +namespace bit_op_local { + +template<bool equalTo8> +struct Tag {}; + +// sizeof(T) < 8 +template<> +struct Tag<false> { + template<class T> + static inline int bsf(T x) + { +#if defined(_MSC_VER) + unsigned long out; + _BitScanForward(&out, x); +#pragma warning(suppress: 6102) + return out; +#else + return __builtin_ctz(x); +#endif + } + template<class T> + static inline int bsr(T x) + { +#if defined(_MSC_VER) + unsigned long out; + _BitScanReverse(&out, x); +#pragma warning(suppress: 6102) + return out; +#else + return __builtin_clz(x) ^ 0x1f; +#endif + } +}; + +// sizeof(T) == 8 +template<> +struct Tag<true> { + template<class T> + static inline int bsf(T x) + { +#if defined(_MSC_VER) && defined(_WIN64) + unsigned long out; + _BitScanForward64(&out, x); +#pragma warning(suppress: 6102) + return out; +#elif defined(__x86_64__) + return __builtin_ctzll(x); +#else + const uint32_t L = uint32_t(x); + if (L) return Tag<false>::bsf(L); + const uint32_t H = uint32_t(x >> 32); + return Tag<false>::bsf(H) + 32; +#endif + } + template<class T> + static inline int bsr(T x) + { +#if defined(_MSC_VER) && defined(_WIN64) + unsigned long out; + _BitScanReverse64(&out, x); +#pragma warning(suppress: 6102) + return out; +#elif defined(__x86_64__) + return __builtin_clzll(x) ^ 0x3f; +#else + const uint32_t H = uint32_t(x >> 32); + if (H) return Tag<false>::bsr(H) + 32; + const uint32_t L = uint32_t(x); + return Tag<false>::bsr(L); +#endif + } +}; + +} // bit_op_local + +template<class T> +int bsf(T x) +{ + return bit_op_local::Tag<sizeof(T) == 8>::bsf(x); +} +template<class T> +int bsr(T x) +{ + return bit_op_local::Tag<sizeof(T) == 8>::bsr(x); +} + +template<class T> +uint64_t makeBitMask64(T x) +{ + assert(x < 64); + return (uint64_t(1) << x) - 1; +} + +template<class T> +uint32_t popcnt(T x); + +template<> +inline uint32_t popcnt<uint32_t>(uint32_t x) +{ +#if defined(_MSC_VER) + return static_cast<uint32_t>(_mm_popcnt_u32(x)); +#else + return static_cast<uint32_t>(__builtin_popcount(x)); +#endif +} + +template<> +inline uint32_t popcnt<uint64_t>(uint64_t x) +{ +#if defined(__x86_64__) + return static_cast<uint32_t>(__builtin_popcountll(x)); +#elif defined(_WIN64) + return static_cast<uint32_t>(_mm_popcnt_u64(x)); +#else + return popcnt<uint32_t>(static_cast<uint32_t>(x)) + popcnt<uint32_t>(static_cast<uint32_t>(x >> 32)); +#endif +} + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/critical_section.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/critical_section.hpp new file mode 100644 index 000000000..13d7f3a0e --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/critical_section.hpp @@ -0,0 +1,60 @@ +#pragma once +/** + @file + @brief critical section + + @author MITSUNARI Shigeo(@herumi) + @author MITSUNARI Shigeo +*/ +#include <cybozu/mutex.hpp> + +namespace cybozu { + +class ConditionVariableCs; + +namespace thread { + +#ifdef _WIN32 +typedef CRITICAL_SECTION CsHandle; +inline void CsInit(CsHandle& cs) { InitializeCriticalSection(&cs); } +inline void CsLock(CsHandle& cs) { EnterCriticalSection(&cs); } +inline void CsUnlock(CsHandle& cs) { LeaveCriticalSection(&cs); } +inline void CsTerm(CsHandle& cs) { DeleteCriticalSection(&cs); } +#else +typedef pthread_mutex_t CsHandle; +inline void CsInit(CsHandle& cs) { pthread_mutex_init(&cs, NULL); } +inline void CsLock(CsHandle& cs) { pthread_mutex_lock(&cs); } +inline void CsUnlock(CsHandle& cs) { pthread_mutex_unlock(&cs); } +inline void CsTerm(CsHandle& cs) { pthread_mutex_destroy(&cs); } +#endif + +} // cybozu::thread + +class CriticalSection { + friend class cybozu::ConditionVariableCs; +public: + CriticalSection() + { + thread::CsInit(hdl_); + } + ~CriticalSection() + { + thread::CsTerm(hdl_); + } + inline void lock() + { + thread::CsLock(hdl_); + } + inline void unlock() + { + thread::CsUnlock(hdl_); + } +private: + CriticalSection(const CriticalSection&); + CriticalSection& operator=(const CriticalSection&); + thread::CsHandle hdl_; +}; + +typedef cybozu::thread::AutoLockT<cybozu::CriticalSection> AutoLockCs; //!< auto lock critical section + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/crypto.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/crypto.hpp new file mode 100644 index 000000000..d427179d9 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/crypto.hpp @@ -0,0 +1,321 @@ +#pragma once +/** + @file + @brief wrap openssl + @author MITSUNARI Shigeo(@herumi) +*/ + +#include <cybozu/exception.hpp> +#ifdef __APPLE__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +#if 0 //#ifdef __APPLE__ + #define COMMON_DIGEST_FOR_OPENSSL + #include <CommonCrypto/CommonDigest.h> + #include <CommonCrypto/CommonHMAC.h> + #define SHA1 CC_SHA1 + #define SHA224 CC_SHA224 + #define SHA256 CC_SHA256 + #define SHA384 CC_SHA384 + #define SHA512 CC_SHA512 +#else +#include <openssl/hmac.h> +#include <openssl/evp.h> +#include <openssl/sha.h> +#endif +#ifdef _MSC_VER + #include <cybozu/link_libeay32.hpp> +#endif + +namespace cybozu { + +namespace crypto { + +class Hash { +public: + enum Name { + N_SHA1, + N_SHA224, + N_SHA256, + N_SHA384, + N_SHA512 + }; +private: + Name name_; + size_t hashSize_; + union { + SHA_CTX sha1; + SHA256_CTX sha256; + SHA512_CTX sha512; + } ctx_; +public: + static inline size_t getSize(Name name) + { + switch (name) { + case N_SHA1: return SHA_DIGEST_LENGTH; + case N_SHA224: return SHA224_DIGEST_LENGTH; + case N_SHA256: return SHA256_DIGEST_LENGTH; + case N_SHA384: return SHA384_DIGEST_LENGTH; + case N_SHA512: return SHA512_DIGEST_LENGTH; + default: + throw cybozu::Exception("crypto:Hash:getSize") << name; + } + } + static inline const char *getName(Name name) + { + switch (name) { + case N_SHA1: return "sha1"; + case N_SHA224: return "sha224"; + case N_SHA256: return "sha256"; + case N_SHA384: return "sha384"; + case N_SHA512: return "sha512"; + default: + throw cybozu::Exception("crypto:Hash:getName") << name; + } + } + static inline Name getName(const std::string& nameStr) + { + static const struct { + const char *nameStr; + Name name; + } tbl[] = { + { "sha1", N_SHA1 }, + { "sha224", N_SHA224 }, + { "sha256", N_SHA256 }, + { "sha384", N_SHA384 }, + { "sha512", N_SHA512 }, + }; + for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { + if (nameStr == tbl[i].nameStr) return tbl[i].name; + } + throw cybozu::Exception("crypto:Hash:getName") << nameStr; + } + explicit Hash(Name name = N_SHA1) + : name_(name) + , hashSize_(getSize(name)) + { + reset(); + } + void update(const void *buf, size_t bufSize) + { + switch (name_) { + case N_SHA1: SHA1_Update(&ctx_.sha1, buf, bufSize); break; + case N_SHA224: SHA224_Update(&ctx_.sha256, buf, bufSize); break; + case N_SHA256: SHA256_Update(&ctx_.sha256, buf, bufSize); break; + case N_SHA384: SHA384_Update(&ctx_.sha512, buf, bufSize); break; + case N_SHA512: SHA512_Update(&ctx_.sha512, buf, bufSize); break; + } + } + void update(const std::string& buf) + { + update(buf.c_str(), buf.size()); + } + void reset() + { + switch (name_) { + case N_SHA1: SHA1_Init(&ctx_.sha1); break; + case N_SHA224: SHA224_Init(&ctx_.sha256); break; + case N_SHA256: SHA256_Init(&ctx_.sha256); break; + case N_SHA384: SHA384_Init(&ctx_.sha512); break; + case N_SHA512: SHA512_Init(&ctx_.sha512); break; + default: + throw cybozu::Exception("crypto:Hash:rset") << name_; + } + } + /* + md must have hashSize byte + @note clear inner buffer after calling digest + */ + void digest(void *out, const void *buf, size_t bufSize) + { + update(buf, bufSize); + unsigned char *md = reinterpret_cast<unsigned char*>(out); + switch (name_) { + case N_SHA1: SHA1_Final(md, &ctx_.sha1); break; + case N_SHA224: SHA224_Final(md, &ctx_.sha256); break; + case N_SHA256: SHA256_Final(md, &ctx_.sha256); break; + case N_SHA384: SHA384_Final(md, &ctx_.sha512); break; + case N_SHA512: SHA512_Final(md, &ctx_.sha512); break; + default: + throw cybozu::Exception("crypto:Hash:digest") << name_; + } + reset(); + } + std::string digest(const void *buf, size_t bufSize) + { + std::string ret; + ret.resize(hashSize_); + digest(&ret[0], buf, bufSize); + return ret; + } + std::string digest(const std::string& buf = "") + { + return digest(buf.c_str(), buf.size()); + } + /* + out must have necessary size + @note return written size + */ + static inline size_t digest(void *out, Name name, const void *buf, size_t bufSize) + { + unsigned char *md = (unsigned char*)out; + const unsigned char *src = cybozu::cast<const unsigned char *>(buf); + switch (name) { + case N_SHA1: SHA1(src, bufSize, md); return 160 / 8; + case N_SHA224: SHA224(src, bufSize, md); return 224 / 8; + case N_SHA256: SHA256(src, bufSize, md); return 256 / 8; + case N_SHA384: SHA384(src, bufSize, md); return 384 / 8; + case N_SHA512: SHA512(src, bufSize, md); return 512 / 8; + default: + return 0; + } + } + static inline std::string digest(Name name, const void *buf, size_t bufSize) + { + char md[128]; + size_t size = digest(md, name, buf, bufSize); + if (size == 0) throw cybozu::Exception("crypt:Hash:digest") << name; + return std::string(md, size); + } + static inline std::string digest(Name name, const std::string& buf) + { + return digest(name, buf.c_str(), buf.size()); + } +}; + +class Hmac { + const EVP_MD *evp_; +public: + explicit Hmac(Hash::Name name = Hash::N_SHA1) + { + switch (name) { + case Hash::N_SHA1: evp_ = EVP_sha1(); break; + case Hash::N_SHA224: evp_ = EVP_sha224(); break; + case Hash::N_SHA256: evp_ = EVP_sha256(); break; + case Hash::N_SHA384: evp_ = EVP_sha384(); break; + case Hash::N_SHA512: evp_ = EVP_sha512(); break; + default: + throw cybozu::Exception("crypto:Hmac:") << name; + } + } + std::string eval(const std::string& key, const std::string& data) + { + std::string out(EVP_MD_size(evp_) + 1, 0); + unsigned int outLen = 0; + if (HMAC(evp_, key.c_str(), static_cast<int>(key.size()), + cybozu::cast<const uint8_t *>(data.c_str()), data.size(), cybozu::cast<uint8_t *>(&out[0]), &outLen)) { + out.resize(outLen); + return out; + } + throw cybozu::Exception("crypto::Hamc::eval"); + } +}; + +class Cipher { + const EVP_CIPHER *cipher_; + EVP_CIPHER_CTX *ctx_; +public: + enum Name { + N_AES128_CBC, + N_AES192_CBC, + N_AES256_CBC, + N_AES128_ECB, // be carefull to use + N_AES192_ECB, // be carefull to use + N_AES256_ECB, // be carefull to use + }; + static inline size_t getSize(Name name) + { + switch (name) { + case N_AES128_CBC: return 128; + case N_AES192_CBC: return 192; + case N_AES256_CBC: return 256; + case N_AES128_ECB: return 128; + case N_AES192_ECB: return 192; + case N_AES256_ECB: return 256; + default: + throw cybozu::Exception("crypto:Cipher:getSize") << name; + } + } + enum Mode { + Decoding, + Encoding + }; + explicit Cipher(Name name = N_AES128_CBC) + : cipher_(0) + , ctx_(0) + { + ctx_ = EVP_CIPHER_CTX_new(); + if (ctx_ == 0) throw cybozu::Exception("crypto:Cipher:EVP_CIPHER_CTX_new"); + switch (name) { + case N_AES128_CBC: cipher_ = EVP_aes_128_cbc(); break; + case N_AES192_CBC: cipher_ = EVP_aes_192_cbc(); break; + case N_AES256_CBC: cipher_ = EVP_aes_256_cbc(); break; + case N_AES128_ECB: cipher_ = EVP_aes_128_ecb(); break; + case N_AES192_ECB: cipher_ = EVP_aes_192_ecb(); break; + case N_AES256_ECB: cipher_ = EVP_aes_256_ecb(); break; + default: + throw cybozu::Exception("crypto:Cipher:Cipher:name") << (int)name; + } + } + ~Cipher() + { + if (ctx_) EVP_CIPHER_CTX_free(ctx_); + } + /* + @note don't use padding = true + */ + void setup(Mode mode, const std::string& key, const std::string& iv, bool padding = false) + { + const int keyLen = static_cast<int>(key.size()); + const int expectedKeyLen = EVP_CIPHER_key_length(cipher_); + if (keyLen != expectedKeyLen) { + throw cybozu::Exception("crypto:Cipher:setup:keyLen") << keyLen << expectedKeyLen; + } + + int ret = EVP_CipherInit_ex(ctx_, cipher_, NULL, cybozu::cast<const uint8_t*>(key.c_str()), cybozu::cast<const uint8_t*>(iv.c_str()), mode == Encoding ? 1 : 0); + if (ret != 1) { + throw cybozu::Exception("crypto:Cipher:setup:EVP_CipherInit_ex") << ret; + } + ret = EVP_CIPHER_CTX_set_padding(ctx_, padding ? 1 : 0); + if (ret != 1) { + throw cybozu::Exception("crypto:Cipher:setup:EVP_CIPHER_CTX_set_padding") << ret; + } +/* + const int ivLen = static_cast<int>(iv.size()); + const int expectedIvLen = EVP_CIPHER_CTX_iv_length(&ctx_); + if (ivLen != expectedIvLen) { + throw cybozu::Exception("crypto:Cipher:setup:ivLen") << ivLen << expectedIvLen; + } +*/ + } + /* + the size of outBuf must be larger than inBufSize + blockSize + @retval positive or 0 : writeSize(+blockSize) + @retval -1 : error + */ + int update(char *outBuf, const char *inBuf, int inBufSize) + { + int outLen = 0; + int ret = EVP_CipherUpdate(ctx_, cybozu::cast<uint8_t*>(outBuf), &outLen, cybozu::cast<const uint8_t*>(inBuf), inBufSize); + if (ret != 1) return -1; + return outLen; + } + /* + return -1 if padding + @note don't use + */ + int finalize(char *outBuf) + { + int outLen = 0; + int ret = EVP_CipherFinal_ex(ctx_, cybozu::cast<uint8_t*>(outBuf), &outLen); + if (ret != 1) return -1; + return outLen; + } +}; + +} } // cybozu::crypto + +#ifdef __APPLE__ + #pragma GCC diagnostic pop +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/endian.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/endian.hpp new file mode 100644 index 000000000..3f1575c46 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/endian.hpp @@ -0,0 +1,224 @@ +#pragma once + +/** + @file + @brief deal with big and little endian + + @author MITSUNARI Shigeo(@herumi) +*/ +#include <cybozu/inttype.hpp> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +namespace cybozu { + +#ifdef _MSC_VER +inline uint16_t byteSwap(uint16_t x) { return _byteswap_ushort(x); } +inline uint32_t byteSwap(uint32_t x) { return _byteswap_ulong(x); } +inline uint64_t byteSwap(uint64_t x) { return _byteswap_uint64(x); } +#else +#if (((__GNUC__) << 16) + (__GNUC_MINOR__)) >= ((4 << 16) + 8) +inline uint16_t byteSwap(uint16_t x) { return __builtin_bswap16(x); } +#else +inline uint16_t byteSwap(uint16_t x) { return (x >> 8) | (x << 8); } +#endif +inline uint32_t byteSwap(uint32_t x) { return __builtin_bswap32(x); } +inline uint64_t byteSwap(uint64_t x) { return __builtin_bswap64(x); } +#endif + +/** + get 16bit integer as little endian + @param src [in] pointer +*/ +inline uint16_t Get16bitAsLE(const void *src) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + uint16_t x; + memcpy(&x, src, sizeof(x)); + return x; +#else + const uint8_t *p = static_cast<const uint8_t *>(src); + return p[0] | (p[1] << 8); +#endif +} + +/** + get 32bit integer as little endian + @param src [in] pointer +*/ +inline uint32_t Get32bitAsLE(const void *src) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + uint32_t x; + memcpy(&x, src, sizeof(x)); + return x; +#else + const uint8_t *p = static_cast<const uint8_t *>(src); + return Get16bitAsLE(p) | (static_cast<uint32_t>(Get16bitAsLE(p + 2)) << 16); +#endif +} + +/** + get 64bit integer as little endian + @param src [in] pointer +*/ +inline uint64_t Get64bitAsLE(const void *src) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + uint64_t x; + memcpy(&x, src, sizeof(x)); + return x; +#else + const uint8_t *p = static_cast<const uint8_t *>(src); + return Get32bitAsLE(p) | (static_cast<uint64_t>(Get32bitAsLE(p + 4)) << 32); +#endif +} + +/** + get 16bit integer as bit endian + @param src [in] pointer +*/ +inline uint16_t Get16bitAsBE(const void *src) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + uint16_t x; + memcpy(&x, src, sizeof(x)); + return byteSwap(x); +#else + const uint8_t *p = static_cast<const uint8_t *>(src); + return p[1] | (p[0] << 8); +#endif +} + +/** + get 32bit integer as bit endian + @param src [in] pointer +*/ +inline uint32_t Get32bitAsBE(const void *src) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + uint32_t x; + memcpy(&x, src, sizeof(x)); + return byteSwap(x); +#else + const uint8_t *p = static_cast<const uint8_t *>(src); + return Get16bitAsBE(p + 2) | (static_cast<uint32_t>(Get16bitAsBE(p)) << 16); +#endif +} + +/** + get 64bit integer as big endian + @param src [in] pointer +*/ +inline uint64_t Get64bitAsBE(const void *src) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + uint64_t x; + memcpy(&x, src, sizeof(x)); + return byteSwap(x); +#else + const uint8_t *p = static_cast<const uint8_t *>(src); + return Get32bitAsBE(p + 4) | (static_cast<uint64_t>(Get32bitAsBE(p)) << 32); +#endif +} + +/** + set 16bit integer as little endian + @param src [out] pointer + @param x [in] integer +*/ +inline void Set16bitAsLE(void *src, uint16_t x) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + memcpy(src, &x, sizeof(x)); +#else + uint8_t *p = static_cast<uint8_t *>(src); + p[0] = static_cast<uint8_t>(x); + p[1] = static_cast<uint8_t>(x >> 8); +#endif +} +/** + set 32bit integer as little endian + @param src [out] pointer + @param x [in] integer +*/ +inline void Set32bitAsLE(void *src, uint32_t x) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + memcpy(src, &x, sizeof(x)); +#else + uint8_t *p = static_cast<uint8_t *>(src); + p[0] = static_cast<uint8_t>(x); + p[1] = static_cast<uint8_t>(x >> 8); + p[2] = static_cast<uint8_t>(x >> 16); + p[3] = static_cast<uint8_t>(x >> 24); +#endif +} +/** + set 64bit integer as little endian + @param src [out] pointer + @param x [in] integer +*/ +inline void Set64bitAsLE(void *src, uint64_t x) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + memcpy(src, &x, sizeof(x)); +#else + uint8_t *p = static_cast<uint8_t *>(src); + Set32bitAsLE(p, static_cast<uint32_t>(x)); + Set32bitAsLE(p + 4, static_cast<uint32_t>(x >> 32)); +#endif +} +/** + set 16bit integer as big endian + @param src [out] pointer + @param x [in] integer +*/ +inline void Set16bitAsBE(void *src, uint16_t x) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + x = byteSwap(x); + memcpy(src, &x, sizeof(x)); +#else + uint8_t *p = static_cast<uint8_t *>(src); + p[0] = static_cast<uint8_t>(x >> 8); + p[1] = static_cast<uint8_t>(x); +#endif +} +/** + set 32bit integer as big endian + @param src [out] pointer + @param x [in] integer +*/ +inline void Set32bitAsBE(void *src, uint32_t x) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + x = byteSwap(x); + memcpy(src, &x, sizeof(x)); +#else + uint8_t *p = static_cast<uint8_t *>(src); + p[0] = static_cast<uint8_t>(x >> 24); + p[1] = static_cast<uint8_t>(x >> 16); + p[2] = static_cast<uint8_t>(x >> 8); + p[3] = static_cast<uint8_t>(x); +#endif +} +/** + set 64bit integer as big endian + @param src [out] pointer + @param x [in] integer +*/ +inline void Set64bitAsBE(void *src, uint64_t x) +{ +#if CYBOZU_ENDIAN == CYBOZU_ENDIAN_LITTLE + x = byteSwap(x); + memcpy(src, &x, sizeof(x)); +#else + uint8_t *p = static_cast<uint8_t *>(src); + Set32bitAsBE(p, static_cast<uint32_t>(x >> 32)); + Set32bitAsBE(p + 4, static_cast<uint32_t>(x)); +#endif +} + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/exception.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/exception.hpp new file mode 100644 index 000000000..247ba4de0 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/exception.hpp @@ -0,0 +1,252 @@ +#pragma once +/** + @file + @brief definition of abstruct exception class + @author MITSUNARI Shigeo(@herumi) +*/ +#ifdef CYBOZU_MINIMUM_EXCEPTION + +#include <cybozu/inttype.hpp> + +namespace cybozu { + +namespace exception { +inline const char *makeString(const char *, size_t) +{ + return ""; +} + +} // cybozu::exception + +class Exception { +public: + explicit Exception(const char* = 0, bool = true) + { + } + ~Exception() CYBOZU_NOEXCEPT {} + const char *what() const CYBOZU_NOEXCEPT { return "cybozu:Exception"; } + template<class T> + Exception& operator<<(const T&) + { + return *this; + } +}; + +} // cybozu + +#else + +#include <string> +#include <algorithm> +#include <sstream> +#include <errno.h> +#include <stdio.h> +#ifdef _WIN32 + #include <winsock2.h> + #include <windows.h> +#else + #include <string.h> // for strerror_r +#endif +#include <cybozu/inttype.hpp> +#ifdef CYBOZU_EXCEPTION_WITH_STACKTRACE + #include <cybozu/stacktrace.hpp> +#endif + +namespace cybozu { + +const bool DontThrow = true; + +namespace exception { + +/* get max 16 characters to avoid buffer overrun */ +inline std::string makeString(const char *str, size_t size) +{ + return std::string(str, std::min<size_t>(size, 16)); +} + +#ifdef _WIN32 +inline std::string wstr2str(const std::wstring& wstr) +{ + std::string str; + for (size_t i = 0; i < wstr.size(); i++) { + uint16_t c = wstr[i]; + if (c < 0x80) { + str += char(c); + } else { + char buf[16]; + CYBOZU_SNPRINTF(buf, sizeof(buf), "\\u%04x", c); + str += buf; + } + } + return str; +} +#endif + +} // cybozu::exception + +/** + convert errno to string + @param err [in] errno + @note for both windows and linux +*/ +inline std::string ConvertErrorNoToString(int err) +{ + char errBuf[256]; + std::string ret; +#ifdef _WIN32 + if (strerror_s(errBuf, sizeof(errBuf), err) == 0) { + ret = errBuf; + } else { + ret = "err"; + } +#elif defined(_GNU_SOURCE) + ret = ::strerror_r(err, errBuf, sizeof(errBuf)); +#else + if (strerror_r(err, errBuf, sizeof(errBuf)) == 0) { + ret = errBuf; + } else { + ret = "err"; + } +#endif + char buf2[64]; + CYBOZU_SNPRINTF(buf2, sizeof(buf2), "(%d)", err); + ret += buf2; + return ret; +} + +class Exception : public std::exception { + mutable std::string str_; +#ifdef CYBOZU_EXCEPTION_WITH_STACKTRACE + mutable std::string stackTrace_; +#endif +public: + explicit Exception(const std::string& name = "", bool enableStackTrace = true) + : str_(name) + { +#ifdef CYBOZU_EXCEPTION_WITH_STACKTRACE + if (enableStackTrace) stackTrace_ = cybozu::StackTrace().toString(); +#else + cybozu::disable_warning_unused_variable(enableStackTrace); +#endif + } + ~Exception() CYBOZU_NOEXCEPT {} + const char *what() const CYBOZU_NOEXCEPT { return toString().c_str(); } + const std::string& toString() const CYBOZU_NOEXCEPT + { +#ifdef CYBOZU_EXCEPTION_WITH_STACKTRACE + try { + if (!stackTrace_.empty()) { +#ifdef CYBOZU_STACKTRACE_ONELINE + str_ += "\n<<<STACKTRACE>>> "; + str_ += stackTrace_; +#else + str_ += "\n<<<STACKTRACE\n"; + str_ += stackTrace_; + str_ += "\n>>>STACKTRACE"; +#endif + } + } catch (...) { + } + stackTrace_.clear(); +#endif + return str_; + } + Exception& operator<<(const char *s) + { + str_ += ':'; + str_ += s; + return *this; + } + Exception& operator<<(const std::string& s) + { + return operator<<(s.c_str()); + } +#ifdef _WIN32 + Exception& operator<<(const std::wstring& s) + { + return operator<<(cybozu::exception::wstr2str(s)); + } +#endif + template<class T> + Exception& operator<<(const T& x) + { + std::ostringstream os; + os << x; + return operator<<(os.str()); + } +}; + +class ErrorNo { +public: +#ifdef _WIN32 + typedef unsigned int NativeErrorNo; +#else + typedef int NativeErrorNo; +#endif + explicit ErrorNo(NativeErrorNo err) + : err_(err) + { + } + ErrorNo() + : err_(getLatestNativeErrorNo()) + { + } + NativeErrorNo getLatestNativeErrorNo() const + { +#ifdef _WIN32 + return ::GetLastError(); +#else + return errno; +#endif + } + /** + convert NativeErrNo to string(maybe UTF8) + @param err [in] errno + @note Linux : same as ConvertErrorNoToString + Windows : for Win32 API(use en-us) + */ + std::string toString() const + { +#ifdef _WIN32 + const int msgSize = 256; + wchar_t msg[msgSize]; + int size = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, + err_, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + msg, + msgSize, + NULL + ); + if (size <= 0) return ""; + // remove last "\r\n" + if (size > 2 && msg[size - 2] == '\r') { + msg[size - 2] = 0; + size -= 2; + } + std::string ret; + ret.resize(size); + // assume ascii only + for (int i = 0; i < size; i++) { + ret[i] = (char)msg[i]; + } + char buf2[64]; + CYBOZU_SNPRINTF(buf2, sizeof(buf2), "(%u)", err_); + ret += buf2; + return ret; +#else + return ConvertErrorNoToString(err_); +#endif + } +private: + NativeErrorNo err_; +}; + +inline std::ostream& operator<<(std::ostream& os, const cybozu::ErrorNo& self) +{ + return os << self.toString(); +} + +} // cybozu +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/hash.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/hash.hpp new file mode 100644 index 000000000..3fd246fa1 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/hash.hpp @@ -0,0 +1,67 @@ +#pragma once +#include <cybozu/inttype.hpp> + +namespace cybozu { + +template<class Iter> +uint32_t hash32(Iter begin, Iter end, uint32_t v = 0) +{ + if (v == 0) v = 2166136261U; + while (begin != end) { + v ^= *begin++; + v *= 16777619; + } + return v; +} +template<class Iter> +uint64_t hash64(Iter begin, Iter end, uint64_t v = 0) +{ + if (v == 0) v = 14695981039346656037ULL; + while (begin != end) { + v ^= *begin++; + v *= 1099511628211ULL; + } + v ^= v >> 32; + return v; +} +template<class T> +uint32_t hash32(const T *x, size_t n, uint32_t v = 0) +{ + return hash32(x, x + n, v); +} +template<class T> +uint64_t hash64(const T *x, size_t n, uint64_t v = 0) +{ + return hash64(x, x + n, v); +} + +} // cybozu + +namespace boost { + +template<class T> +struct hash; + +} // boost + +#if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11 +#include <functional> +#else + +namespace std { CYBOZU_NAMESPACE_TR1_BEGIN + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4099) // missmatch class and struct +#endif +#ifndef __APPLE__ +template<class T> +struct hash; +#endif +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +CYBOZU_NAMESPACE_TR1_END } // std + +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/inttype.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/inttype.hpp new file mode 100644 index 000000000..62856bdb3 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/inttype.hpp @@ -0,0 +1,163 @@ +#pragma once +/** + @file + @brief int type definition and macros + @author MITSUNARI Shigeo(@herumi) +*/ + +#if defined(_MSC_VER) && (MSC_VER <= 1500) && !defined(CYBOZU_DEFINED_INTXX) + #define CYBOZU_DEFINED_INTXX + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned short uint16_t; + typedef short int16_t; + typedef unsigned char uint8_t; + typedef signed char int8_t; +#else + #include <stdint.h> +#endif + +#ifdef _MSC_VER + #ifndef CYBOZU_DEFINED_SSIZE_T + #define CYBOZU_DEFINED_SSIZE_T + #ifdef _WIN64 + typedef int64_t ssize_t; + #else + typedef int32_t ssize_t; + #endif + #endif +#else + #include <unistd.h> // for ssize_t +#endif + +#ifndef CYBOZU_ALIGN + #ifdef _MSC_VER + #define CYBOZU_ALIGN(x) __declspec(align(x)) + #else + #define CYBOZU_ALIGN(x) __attribute__((aligned(x))) + #endif +#endif +#ifndef CYBOZU_FORCE_INLINE + #ifdef _MSC_VER + #define CYBOZU_FORCE_INLINE __forceinline + #else + #define CYBOZU_FORCE_INLINE __attribute__((always_inline)) + #endif +#endif +#ifndef CYBOZU_UNUSED + #ifdef __GNUC__ + #define CYBOZU_UNUSED __attribute__((unused)) + #else + #define CYBOZU_UNUSED + #endif +#endif +#ifndef CYBOZU_ALLOCA + #ifdef _MSC_VER + #include <malloc.h> + #define CYBOZU_ALLOCA(x) _malloca(x) + #else + #define CYBOZU_ALLOCA(x) __builtin_alloca(x) + #endif +#endif +#ifndef CYBOZU_NUM_OF_ARRAY + #define CYBOZU_NUM_OF_ARRAY(x) (sizeof(x) / sizeof(*x)) +#endif +#ifndef CYBOZU_SNPRINTF + #if defined(_MSC_VER) && (_MSC_VER < 1900) + #define CYBOZU_SNPRINTF(x, len, ...) (void)_snprintf_s(x, len, len - 1, __VA_ARGS__) + #else + #define CYBOZU_SNPRINTF(x, len, ...) (void)snprintf(x, len, __VA_ARGS__) + #endif +#endif + +#define CYBOZU_CPP_VERSION_CPP03 0 +#define CYBOZU_CPP_VERSION_TR1 1 +#define CYBOZU_CPP_VERSION_CPP11 2 +#define CYBOZU_CPP_VERSION_CPP14 3 +#define CYBOZU_CPP_VERSION_CPP17 4 + +#ifdef __GNUC__ + #define CYBOZU_GNUC_PREREQ(major, minor) ((__GNUC__) * 100 + (__GNUC_MINOR__) >= (major) * 100 + (minor)) +#else + #define CYBOZU_GNUC_PREREQ(major, minor) 0 +#endif + +#if (__cplusplus >= 201703) + #define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_CPP17 +#elif (__cplusplus >= 201402) + #define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_CPP14 +#elif (__cplusplus >= 201103) || (_MSC_VER >= 1500) || defined(__GXX_EXPERIMENTAL_CXX0X__) + #if defined(_MSC_VER) && (_MSC_VER <= 1600) + #define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_TR1 + #else + #define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_CPP11 + #endif +#elif CYBOZU_GNUC_PREREQ(4, 5) || (CYBOZU_GNUC_PREREQ(4, 2) && __GLIBCXX__ >= 20070719) || defined(__INTEL_COMPILER) || (__clang_major__ >= 3) + #define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_TR1 +#else + #define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_CPP03 +#endif + +#ifdef CYBOZU_USE_BOOST + #define CYBOZU_NAMESPACE_STD boost + #define CYBOZU_NAMESPACE_TR1_BEGIN + #define CYBOZU_NAMESPACE_TR1_END +#elif (CYBOZU_CPP_VERSION == CYBOZU_CPP_VERSION_TR1) && !defined(__APPLE__) + #define CYBOZU_NAMESPACE_STD std::tr1 + #define CYBOZU_NAMESPACE_TR1_BEGIN namespace tr1 { + #define CYBOZU_NAMESPACE_TR1_END } +#else + #define CYBOZU_NAMESPACE_STD std + #define CYBOZU_NAMESPACE_TR1_BEGIN + #define CYBOZU_NAMESPACE_TR1_END +#endif + +#ifndef CYBOZU_OS_BIT + #if defined(_WIN64) || defined(__x86_64__) || defined(__AARCH64EL__) || defined(__EMSCRIPTEN__) + #define CYBOZU_OS_BIT 64 + #else + #define CYBOZU_OS_BIT 32 + #endif +#endif + +#ifndef CYBOZU_HOST + #define CYBOZU_HOST_UNKNOWN 0 + #define CYBOZU_HOST_INTEL 1 + #define CYBOZU_HOST_ARM 2 + #if defined(_M_IX86) || defined(_M_AMD64) || defined(__x86_64__) || defined(__i386__) + #define CYBOZU_HOST CYBOZU_HOST_INTEL + #elif defined(__arm__) || defined(__AARCH64EL__) + #define CYBOZU_HOST CYBOZU_HOST_ARM + #else + #define CYBOZU_HOST CYBOZU_HOST_UNKNOWN + #endif +#endif + +#ifndef CYBOZU_ENDIAN + #define CYBOZU_ENDIAN_UNKNOWN 0 + #define CYBOZU_ENDIAN_LITTLE 1 + #define CYBOZU_ENDIAN_BIG 2 + #if (CYBOZU_HOST == CYBOZU_HOST_INTEL) + #define CYBOZU_ENDIAN CYBOZU_ENDIAN_LITTLE + #elif (CYBOZU_HOST == CYBOZU_HOST_ARM) && (defined(__ARM_EABI__) || defined(__AARCH64EL__)) + #define CYBOZU_ENDIAN CYBOZU_ENDIAN_LITTLE + #else + #define CYBOZU_ENDIAN CYBOZU_ENDIAN_UNKNOWN + #endif +#endif + +#if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11 + #define CYBOZU_NOEXCEPT noexcept +#else + #define CYBOZU_NOEXCEPT throw() +#endif +namespace cybozu { +template<class T> +void disable_warning_unused_variable(const T&) { } +template<class T, class S> +T cast(const S* ptr) { return static_cast<T>(static_cast<const void*>(ptr)); } +template<class T, class S> +T cast(S* ptr) { return static_cast<T>(static_cast<void*>(ptr)); } +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/itoa.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/itoa.hpp new file mode 100644 index 000000000..072e5b8b4 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/itoa.hpp @@ -0,0 +1,337 @@ +#pragma once +/** + @file + @brief convert integer to string(ascii) + + @author MITSUNARI Shigeo(@herumi) +*/ +#include <limits.h> +#ifndef CYBOZU_DONT_USE_STRING +#include <string> +#endif +#include <memory.h> +#include <cybozu/inttype.hpp> +#include <cybozu/bit_operation.hpp> + +namespace cybozu { + +template<class T> +size_t getHexLength(T x) +{ + return x == 0 ? 1 : cybozu::bsr(x) / 4 + 1; +} + +template<class T> +size_t getBinLength(T x) +{ + return x == 0 ? 1 : cybozu::bsr(x) + 1; +} +/* + convert x to hex string with len + @note out should have getHexLength(x) size + out is not NUL terminated +*/ +template<class T> +void itohex(char *out, size_t len, T x, bool upCase = true) +{ + static const char *hexTbl[] = { + "0123456789abcdef", + "0123456789ABCDEF" + }; + const char *tbl = hexTbl[upCase]; + for (size_t i = 0; i < len; i++) { + out[len - i - 1] = tbl[x % 16]; + x /= 16; + } +} +/* + convert x to bin string with len + @note out should have getBinLength(x) size + out is not NUL terminated +*/ +template<class T> +void itobin(char *out, size_t len, T x) +{ + for (size_t i = 0; i < len; i++) { + out[len - i - 1] = '0' + (x & 1); + x >>= 1; + } +} + +namespace itoa_local { + +/* + convert x to dec + use buf[0, bufSize) + return 0 if false + return writtenSize which is not terminated + @REMARK the top of string is buf + bufSize - writtenSize +*/ +template<class UT> +size_t uintToDec(char *buf, size_t bufSize, UT x) +{ + for (size_t i = 0; i < bufSize; i++) { + buf[bufSize - 1 - i] = '0' + static_cast<int>(x % 10); + x /= 10; + if (x == 0) return i + 1; + } + return 0; +} + +/* + convert x to hex + use buf[0, bufSize) + return 0 if false + return writtenSize which is not terminated + @REMARK the top of string is buf + bufSize - writtenSize +*/ +template<class UT> +size_t uintToHex(char *buf, size_t bufSize, UT x, bool upCase = true) +{ + static const char *hexTbl[] = { + "0123456789abcdef", + "0123456789ABCDEF" + }; + const char *tbl = hexTbl[upCase]; + for (size_t i = 0; i < bufSize; i++) { + buf[bufSize - 1 - i] = tbl[x % 16]; + x /= 16; + if (x == 0) return i + 1; + } + return 0; +} + +/* + convert x to bin + use buf[0, bufSize) + return 0 if false + return writtenSize which is not terminated + @REMARK the top of string is buf + bufSize - writtenSize +*/ +template<class UT> +size_t uintToBin(char *buf, size_t bufSize, UT x) +{ + for (size_t i = 0; i < bufSize; i++) { + buf[bufSize - 1 - i] = '0' + (x & 1); + x >>= 1; + if (x == 0) return i + 1; + } + return 0; +} + +template<class T> +size_t intToDec(char *buf, size_t bufSize, T x) +{ + if (x == LLONG_MIN) { + const char minStr[] = "-9223372036854775808"; + const size_t minStrLen = sizeof(minStr) - 1; + if (bufSize < minStrLen) { + return 0; + } else { + memcpy(buf + bufSize - minStrLen, minStr, minStrLen); + return minStrLen; + } + } + bool negative = x < 0; + uint64_t absX = negative ? -x : x; + size_t n = uintToDec(buf, bufSize, absX); + if (n == 0) return 0; + if (negative) { + if (bufSize == n) return 0; + n++; + buf[bufSize - n] = '-'; + } + return n; +} + +#ifndef CYBOZU_DONT_USE_STRING +template<typename T> +void convertFromUint(std::string& out, T x) +{ + char buf[40]; + size_t n = uintToDec(buf, sizeof(buf), x); + assert(n > 0); + out.assign(buf + sizeof(buf) - n, n); +} + +inline void convertFromInt(std::string& out, long long x) +{ + char buf[40]; + size_t n = intToDec(buf, sizeof(buf), x); + assert(n > 0); + out.assign(buf + sizeof(buf) - n, n); +} + +template<typename T> +void itohexLocal(std::string& out, T x, bool upCase, bool withZero) +{ + const size_t size = withZero ? sizeof(T) * 2 : getHexLength(x); + out.resize(size); + itohex(&out[0], size, x, upCase); +} + +template<class T> +void itobinLocal(std::string& out, T x, bool withZero) +{ + const size_t size = withZero ? sizeof(T) * 8 : getBinLength(x); + out.resize(size); + itobin(&out[0], size, x); +} +#endif + +} // itoa_local + +#ifndef CYBOZU_DONT_USE_STRING +/** + convert int to string + @param out [out] string + @param x [in] int +*/ +inline void itoa(std::string& out, int x) +{ + itoa_local::convertFromInt(out, x); +} + +/** + convert long long to string + @param out [out] string + @param x [in] long long +*/ +inline void itoa(std::string& out, long long x) +{ + itoa_local::convertFromInt(out, x); +} + +/** + convert unsigned int to string + @param out [out] string + @param x [in] unsigned int +*/ +inline void itoa(std::string& out, unsigned int x) +{ + itoa_local::convertFromUint(out, x); +} + +/** + convert unsigned long long to string + @param out [out] string + @param x [in] unsigned long long +*/ +inline void itoa(std::string& out, unsigned long long x) +{ + itoa_local::convertFromUint(out, x); +} + +#if defined(__SIZEOF_LONG__) && (__SIZEOF_LONG__ == 8) +inline void itoa(std::string& out, long x) { itoa(out, static_cast<long long>(x)); } +inline void itoa(std::string& out, unsigned long x) { itoa(out, static_cast<unsigned long long>(x)); } +#else +inline void itoa(std::string& out, long x) { itoa(out, static_cast<int>(x)); } +inline void itoa(std::string& out, unsigned long x) { itoa(out, static_cast<int>(x)); } +#endif +/** + convert integer to string + @param x [in] int +*/ +template<typename T> +inline std::string itoa(T x) +{ + std::string ret; + itoa(ret, x); + return ret; +} + +inline void itohex(std::string& out, unsigned char x, bool upCase = true, bool withZero = true) +{ + itoa_local::itohexLocal(out, x, upCase, withZero); +} + +inline void itohex(std::string& out, unsigned short x, bool upCase = true, bool withZero = true) +{ + itoa_local::itohexLocal(out, x, upCase, withZero); +} + +inline void itohex(std::string& out, unsigned int x, bool upCase = true, bool withZero = true) +{ + itoa_local::itohexLocal(out, x, upCase, withZero); +} + +inline void itohex(std::string& out, unsigned long x, bool upCase = true, bool withZero = true) +{ + itoa_local::itohexLocal(out, x, upCase, withZero); +} + +inline void itohex(std::string& out, unsigned long long x, bool upCase = true, bool withZero = true) +{ + itoa_local::itohexLocal(out, x, upCase, withZero); +} + +template<typename T> +inline std::string itobin(T x, bool withZero = true) +{ + std::string out; + itoa_local::itobinLocal(out, x, withZero); + return out; +} + +inline void itobin(std::string& out, unsigned char x, bool withZero = true) +{ + itoa_local::itobinLocal(out, x, withZero); +} + +inline void itobin(std::string& out, unsigned short x, bool withZero = true) +{ + itoa_local::itobinLocal(out, x, withZero); +} + +inline void itobin(std::string& out, unsigned int x, bool withZero = true) +{ + itoa_local::itobinLocal(out, x, withZero); +} + +inline void itobin(std::string& out, unsigned long x, bool withZero = true) +{ + itoa_local::itobinLocal(out, x, withZero); +} + +inline void itobin(std::string& out, unsigned long long x, bool withZero = true) +{ + itoa_local::itobinLocal(out, x, withZero); +} + +template<typename T> +inline std::string itohex(T x, bool upCase = true, bool withZero = true) +{ + std::string out; + itohex(out, x, upCase, withZero); + return out; +} +/** + convert integer to string with zero padding + @param x [in] int + @param len [in] minimum lengh of string + @param c [in] padding character + @note + itoa(12, 4) == "0012" + itoa(1234, 4) == "1234" + itoa(12345, 4) == "12345" + itoa(-12, 4) == "-012" +*/ +template<typename T> +inline std::string itoaWithZero(T x, size_t len, char c = '0') +{ + std::string ret; + itoa(ret, x); + if (ret.size() < len) { + std::string zero(len - ret.size(), c); + if (x >= 0) { + ret = zero + ret; + } else { + ret = "-" + zero + ret.substr(1); + } + } + return ret; +} +#endif + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_libeay32.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_libeay32.hpp new file mode 100644 index 000000000..d83f1b6ea --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_libeay32.hpp @@ -0,0 +1,21 @@ +#pragma once +/** + @file + @brief link libeay32.lib of openssl + @author MITSUNARI Shigeo(@herumi) +*/ +#if defined(_WIN32) && defined(_MT) + #if _MSC_VER >= 1900 // VC2015 + #ifdef _WIN64 + #pragma comment(lib, "mt/14/libeay32.lib") + #else + #pragma comment(lib, "mt/14/32/libeay32.lib") + #endif +// #elif _MSC_VER == 1800 // VC2013 + #else + #pragma comment(lib, "mt/12/libeay32.lib") + #endif + #pragma comment(lib, "advapi32.lib") + #pragma comment(lib, "gdi32.lib") + #pragma comment(lib, "user32.lib") +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_mpir.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_mpir.hpp new file mode 100644 index 000000000..d20d7b1a9 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_mpir.hpp @@ -0,0 +1,18 @@ +#pragma once +/** + @file + @brief link mpir/mpirxx of mpir + @author MITSUNARI Shigeo(@herumi) +*/ +#if defined(_WIN32) && defined(_MT) + #if _MSC_VER >= 1900 // VC2015, VC2017(1910) + #pragma comment(lib, "mt/14/mpir.lib") + #pragma comment(lib, "mt/14/mpirxx.lib") + #elif _MSC_VER == 1800 // VC2013 + #pragma comment(lib, "mt/12/mpir.lib") + #pragma comment(lib, "mt/12/mpirxx.lib") + #elif _MSC_VER == 1700 // VC2012 + #pragma comment(lib, "mt/11/mpir.lib") + #pragma comment(lib, "mt/11/mpirxx.lib") + #endif +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_ssleay32.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_ssleay32.hpp new file mode 100644 index 000000000..60c2361ae --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/link_ssleay32.hpp @@ -0,0 +1,19 @@ +#pragma once +/** + @file + @brief link ssleay32.lib of openssl + @author MITSUNARI Shigeo(@herumi) +*/ +#if defined(_WIN32) && defined(_MT) + #if _MSC_VER >= 1900 // VC2015 + #ifdef _WIN64 + #pragma comment(lib, "mt/14/ssleay32.lib") + #else + #pragma comment(lib, "mt/14/32/ssleay32.lib") + #endif +// #elif _MSC_VER == 1800 // VC2013 + #else + #pragma comment(lib, "mt/12/ssleay32.lib") + #endif + #pragma comment(lib, "user32.lib") +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/mutex.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/mutex.hpp new file mode 100644 index 000000000..acde6bcbf --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/mutex.hpp @@ -0,0 +1,141 @@ +#pragma once +/** + @file + @brief mutex + + @author MITSUNARI Shigeo(@herumi) + @author MITSUNARI Shigeo +*/ + +#ifdef _WIN32 + #include <windows.h> +#else + #include <pthread.h> + #include <time.h> +#endif +#include <assert.h> +#include <stdlib.h> + +namespace cybozu { + +class ConditionVariable; + +namespace thread { + +#ifdef _WIN32 + typedef HANDLE MutexHandle; + inline void MutexInit(MutexHandle& mutex) + { +// mutex = CreateSemaphore(NULL /* no security */, 1 /* init */, 0x7FFFFFFF /* max */, NULL /* no name */); + mutex = CreateMutex(NULL /* no security */, FALSE /* no owner */, NULL /* no name */); + } + inline void MutexLock(MutexHandle& mutex) { WaitForSingleObject(mutex, INFINITE); } + /* + return false if timeout + @param msec [in] msec + */ + inline bool MutexLockTimeout(MutexHandle& mutex, int msec) + { + DWORD ret = WaitForSingleObject(mutex, msec); + if (ret == WAIT_OBJECT_0) { + return true; + } + if (ret == WAIT_TIMEOUT) { + return false; + } + /* ret == WAIT_ABANDONED */ + assert(0); + return false; + } + inline void MutexUnlock(MutexHandle& mutex) + { +// ReleaseSemaphore(mutex, 1, NULL); + ReleaseMutex(mutex); + } + inline void MutexTerm(MutexHandle& mutex) { CloseHandle(mutex); } +#else + typedef pthread_mutex_t MutexHandle; + inline void MutexInit(MutexHandle& mutex) + { +#if 1 + pthread_mutex_init(&mutex, NULL); +#else + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP)) { + perror("pthread_mutexattr_settype"); + exit(1); + } + pthread_mutex_init(&mutex, &attr); + pthread_mutexattr_destroy(&attr); +#endif + } + inline void MutexLock(MutexHandle& mutex) { pthread_mutex_lock(&mutex); } +#if 0 + inline bool MutexLockTimeout(MutexHandle& mutex, int msec) + { + timespec absTime; + clock_gettime(CLOCK_REALTIME, &absTime); + absTime.tv_sec += msec / 1000; + absTime.tv_nsec += msec % 1000; + bool ret = pthread_mutex_timedlock(&mutex, &absTime) == 0; + return ret; + } +#endif + inline void MutexUnlock(MutexHandle& mutex) { pthread_mutex_unlock(&mutex); } + inline void MutexTerm(MutexHandle& mutex) { pthread_mutex_destroy(&mutex); } +#endif + +template<class T> +class AutoLockT { +public: + explicit AutoLockT(T &t) + : t_(t) + { + t_.lock(); + } + ~AutoLockT() + { + t_.unlock(); + } +private: + T& t_; + AutoLockT& operator=(const AutoLockT&); +}; + +} // cybozu::thread + +class Mutex { + friend class cybozu::ConditionVariable; +public: + Mutex() + { + thread::MutexInit(hdl_); + } + ~Mutex() + { + thread::MutexTerm(hdl_); + } + void lock() + { + thread::MutexLock(hdl_); + } +#if 0 + bool lockTimeout(int msec) + { + return thread::MutexLockTimeout(hdl_, msec); + } +#endif + void unlock() + { + thread::MutexUnlock(hdl_); + } +private: + Mutex(const Mutex&); + Mutex& operator=(const Mutex&); + thread::MutexHandle hdl_; +}; + +typedef cybozu::thread::AutoLockT<cybozu::Mutex> AutoLock; + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/option.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/option.hpp new file mode 100644 index 000000000..a5dfd137d --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/option.hpp @@ -0,0 +1,723 @@ +#pragma once +/** + @file + @brief command line parser + + @author MITSUNARI Shigeo(@herumi) +*/ +#include <string> +#include <vector> +#include <map> +#include <sstream> +#include <iostream> +#include <limits> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <cybozu/exception.hpp> +#include <cybozu/atoi.hpp> + +/* + Option parser + + progName (opt1-name|opt2-name|...) param1 param2 ... + param1:param1-help + param2:param2-help + -op1-name:opt1-help + ... + + How to setup + int num; + -n num ; (optional) option => appendOpt(&x, <defaultValue>, "num", "num-help"); + -n num ; must option => appendMust(&x, "num", "num-help"); + + std::vector<int> v; + -v s1 s2 s3 ... => appendVec(&v, "v"); + + Remark1: terminate parsing of v if argv begins with '-[^0-9]' + Remark2: the begining character of opt-name is not a number ('0'...'9') + because avoid conflict with minus number + + std::string file1; + file1 is param => appendParam(&file1, "input-file"); + file2 is optional param => appendParamOpt(&file2, "output-file"); + + How to use + opt.parse(argc, argv); + + see sample/option_smpl.cpp +*/ + +namespace cybozu { + +struct OptionError : public cybozu::Exception { + enum Type { + NoError = 0, + BAD_OPT = 1, + BAD_VALUE, + NO_VALUE, + OPT_IS_NECESSARY, + PARAM_IS_NECESSARY, + REDUNDANT_VAL, + BAD_ARGC + }; + Type type; + int argPos; + OptionError() + : cybozu::Exception("OptionError", false) + , type(NoError) + , argPos(0) + { + } + cybozu::Exception& set(Type _type, int _argPos = 0) + { + this->type = _type; + this->argPos = _argPos; + switch (_type) { + case BAD_OPT: + (*this) << "bad opt"; + break; + case BAD_VALUE: + (*this) << "bad value"; + break; + case NO_VALUE: + (*this) << "no value"; + break; + case OPT_IS_NECESSARY: + (*this) << "opt is necessary"; + break; + case PARAM_IS_NECESSARY: + (*this) << "param is necessary"; + break; + case REDUNDANT_VAL: + (*this) << "redundant argVal"; + break; + case BAD_ARGC: + (*this) << "bad argc"; + default: + break; + } + return *this; + } +}; + +namespace option_local { + +template<class T> +bool convert(T* x, const char *str) +{ + std::istringstream is(str); + is >> *x; + return !!is; +} + +template<> +inline bool convert(std::string* x, const char *str) +{ + *x = str; + return true; +} + +template<class T> +bool convertInt(T* x, const char *str) +{ + if (str[0] == '0' && str[1] == 'x') { + bool b; + *x = cybozu::hextoi(&b, str + 2); + return b; + } + size_t len = strlen(str); + int factor = 1; + if (len > 1) { + switch (str[len - 1]) { + case 'k': factor = 1000; len--; break; + case 'm': factor = 1000 * 1000; len--; break; + case 'g': factor = 1000 * 1000 * 1000; len--; break; + case 'K': factor = 1024; len--; break; + case 'M': factor = 1024 * 1024; len--; break; + case 'G': factor = 1024 * 1024 * 1024; len--; break; + default: break; + } + } + bool b; + T y = cybozu::atoi(&b, str, len); + if (!b) return false; + if (factor > 1) { + if ((std::numeric_limits<T>::min)() / factor <= y + && y <= (std::numeric_limits<T>::max)() / factor) { + *x = y * factor; + } else { + return false; + } + } else { + *x = y; + } + return true; +} + +#define CYBOZU_OPTION_DEFINE_CONVERT_INT(type) \ +template<>inline bool convert(type* x, const char *str) { return convertInt(x, str); } + +CYBOZU_OPTION_DEFINE_CONVERT_INT(int) +CYBOZU_OPTION_DEFINE_CONVERT_INT(long) +CYBOZU_OPTION_DEFINE_CONVERT_INT(long long) + +CYBOZU_OPTION_DEFINE_CONVERT_INT(unsigned int) +CYBOZU_OPTION_DEFINE_CONVERT_INT(unsigned long) +CYBOZU_OPTION_DEFINE_CONVERT_INT(unsigned long long) + +#undef CYBOZU_OPTION_DEFINE_CONVERT_INT + +struct HolderBase { + virtual ~HolderBase(){} + virtual bool set(const char*) = 0; + virtual HolderBase *clone() const = 0; + virtual std::string toStr() const = 0; + virtual const void *get() const = 0; +}; + +template<class T> +struct Holder : public HolderBase { + T *p_; + Holder(T *p) : p_(p) {} + HolderBase *clone() const { return new Holder(p_); } + bool set(const char *str) { return option_local::convert(p_, str); } + std::string toStr() const + { + std::ostringstream os; + os << *p_; + return os.str(); + } + const void *get() const { return (void*)p_; } +}; + +/* + for gcc 7 with -fnew-ttp-matching + this specialization is not necessary under -fno-new-ttp-matching +*/ +template struct Holder<std::string>; + +template<class T, class Alloc, template<class T_, class Alloc_>class Container> +struct Holder<Container<T, Alloc> > : public HolderBase { + typedef Container<T, Alloc> Vec; + Vec *p_; + Holder(Vec *p) : p_(p) {} + HolderBase *clone() const { return new Holder<Vec>(p_); } + bool set(const char *str) + { + T t; + bool b = option_local::convert(&t, str); + if (b) p_->push_back(t); + return b; + } + std::string toStr() const + { + std::ostringstream os; + bool isFirst = true; + for (typename Vec::const_iterator i = p_->begin(), ie = p_->end(); i != ie; ++i) { + if (isFirst) { + isFirst = false; + } else { + os << ' '; + } + os << *i; + } + return os.str(); + } + const void *get() const { return (void*)p_; } +}; + +class Var { + HolderBase *p_; + bool isSet_; +public: + Var() : p_(0), isSet_(false) { } + Var(const Var& rhs) : p_(rhs.p_->clone()), isSet_(false) { } + template<class T> + explicit Var(T *x) : p_(new Holder<T>(x)), isSet_(false) { } + + ~Var() { delete p_; } + + void swap(Var& rhs) CYBOZU_NOEXCEPT + { + std::swap(p_, rhs.p_); + std::swap(isSet_, rhs.isSet_); + } + void operator=(const Var& rhs) + { + Var v(rhs); + swap(v); + } + bool set(const char *str) + { + isSet_ = true; + return p_->set(str); + } + std::string toStr() const { return p_ ? p_->toStr() : ""; } + bool isSet() const { return isSet_; } + const void *get() const { return p_ ? p_->get() : 0; } +}; + +} // option_local + +class Option { + enum Mode { // for opt + N_is0 = 0, // for bool by appendBoolOpt() + N_is1 = 1, + N_any = 2 + }; + enum ParamMode { + P_exact = 0, // one + P_optional = 1, // zero or one + P_variable = 2 // zero or greater + }; + struct Info { + option_local::Var var; + Mode mode; // 0 or 1 or any ; for opt, not used for Param + bool isMust; // this option is must + std::string opt; // option param name without '-' + std::string help; // description of option + + Info() : mode(N_is0), isMust(false) {} + template<class T> + Info(T* pvar, Mode mode, bool isMust, const char *opt, const std::string& help) + : var(pvar) + , mode(mode) + , isMust(isMust) + , opt(opt) + , help(help) + { + } + friend inline std::ostream& operator<<(std::ostream& os, const Info& self) + { + os << self.opt << '=' << self.var.toStr(); + if (self.var.isSet()) { + os << " (set)"; + } else { + os << " (default)"; + } + return os; + } + void put() const + { + std::cout << *this; + } + void usage() const + { + printf(" -%s %s%s\n", opt.c_str(), help.c_str(), isMust ? " (must)" : ""); + } + void shortUsage() const + { + printf(" -%s %s", opt.c_str(), mode == N_is0 ? "" : mode == N_is1 ? "para" : "para..."); + } + bool isSet() const { return var.isSet(); } + const void *get() const { return var.get(); } + }; + typedef std::vector<Info> InfoVec; + typedef std::vector<std::string> StrVec; + typedef std::map<std::string, size_t> OptMap; + InfoVec infoVec_; + InfoVec paramVec_; + Info remains_; + OptMap optMap_; + bool showOptUsage_; + ParamMode paramMode_; + std::string progName_; + std::string desc_; + std::string helpOpt_; + std::string help_; + std::string usage_; + StrVec delimiters_; + StrVec *remainsAfterDelimiter_; + int nextDelimiter_; + template<class T> + void appendSub(T *pvar, Mode mode, bool isMust, const char *opt, const std::string& help) + { + const char c = opt[0]; + if ('0' <= c && c <= '9') throw cybozu::Exception("Option::appendSub:opt must begin with not number") << opt; + if (optMap_.find(opt) != optMap_.end()) { + throw cybozu::Exception("Option::append:duplicate option") << opt; + } + optMap_[opt] = infoVec_.size(); + infoVec_.push_back(Info(pvar, mode, isMust, opt, help)); + } + + template<class T, class U> + void append(T *pvar, const U& defaultVal, bool isMust, const char *opt, const std::string& help = "") + { + *pvar = defaultVal; + appendSub(pvar, N_is1, isMust, opt, help); + } + /* + don't deal with negative number as option + */ + bool isOpt(const char *str) const + { + if (str[0] != '-') return false; + const char c = str[1]; + if ('0' <= c && c <= '9') return false; + return true; + } + void verifyParamMode() + { + if (paramMode_ != P_exact) throw cybozu::Exception("Option:appendParamVec:appendParam is forbidden after appendParamOpt/appendParamVec"); + } + std::string getBaseName(const std::string& name) const + { + size_t pos = name.find_last_of("/\\"); + if (pos == std::string::npos) return name; + return name.substr(pos + 1); + } + bool inDelimiters(const std::string& str) const + { + return std::find(delimiters_.begin(), delimiters_.end(), str) != delimiters_.end(); + } +public: + Option() + : showOptUsage_(true) + , paramMode_(P_exact) + , remainsAfterDelimiter_(0) + , nextDelimiter_(-1) + { + } + virtual ~Option() {} + /* + append optional option with default value + @param pvar [in] pointer to option variable + @param defaultVal [in] default value + @param opt [in] option name + @param help [in] option help + @note you can use 123k, 56M if T is int/long/long long + k : *1000 + m : *1000000 + g : *1000000000 + K : *1024 + M : *1024*1024 + G : *1024*1024*1024 + */ + template<class T, class U> + void appendOpt(T *pvar, const U& defaultVal, const char *opt, const std::string& help = "") + { + append(pvar, defaultVal, false, opt, help); + } + /* + default value of *pvar is false + */ + void appendBoolOpt(bool *pvar, const char *opt, const std::string& help = "") + { + *pvar = false; + appendSub(pvar, N_is0, false, opt, help); + } + /* + append necessary option + @param pvar [in] pointer to option variable + @param opt [in] option name + @param help [in] option help + */ + template<class T> + void appendMust(T *pvar, const char *opt, const std::string& help = "") + { + append(pvar, T(), true, opt, help); + } + /* + append vector option + @param pvar [in] pointer to option variable + @param opt [in] option name + @param help [in] option help + */ + template<class T, class Alloc, template<class T_, class Alloc_>class Container> + void appendVec(Container<T, Alloc> *pvar, const char *opt, const std::string& help = "") + { + appendSub(pvar, N_any, false, opt, help); + } + /* + append parameter + @param pvar [in] pointer to parameter + @param opt [in] option name + @param help [in] option help + */ + template<class T> + void appendParam(T *pvar, const char *opt, const std::string& help = "") + { + verifyParamMode(); + paramVec_.push_back(Info(pvar, N_is1, true, opt, help)); + } + /* + append optional parameter + @param pvar [in] pointer to parameter + @param defaultVal [in] default value + @param opt [in] option name + @param help [in] option help + @note you can call appendParamOpt once after appendParam + */ + template<class T, class U> + void appendParamOpt(T *pvar, const U& defaultVal, const char *opt, const std::string& help = "") + { + verifyParamMode(); + *pvar = defaultVal; + paramMode_ = P_optional; + paramVec_.push_back(Info(pvar, N_is1, false, opt, help)); + } + /* + append remain parameter + @param pvar [in] pointer to vector of parameter + @param opt [in] option name + @param help [in] option help + @note you can call appendParamVec once after appendParam + */ + template<class T, class Alloc, template<class T_, class Alloc_>class Container> + void appendParamVec(Container<T, Alloc> *pvar, const char *name, const std::string& help = "") + { + verifyParamMode(); + paramMode_ = P_variable; + remains_.var = option_local::Var(pvar); + remains_.mode = N_any; + remains_.isMust = false; + remains_.opt = name; + remains_.help = help; + } + void appendHelp(const char *opt, const std::string& help = ": show this message") + { + helpOpt_ = opt; + help_ = help; + } + /* + stop parsing after delimiter is found + @param delimiter [in] string to stop + @param remain [out] set remaining strings if remain + */ + void setDelimiter(const std::string& delimiter, std::vector<std::string> *remain = 0) + { + delimiters_.push_back(delimiter); + remainsAfterDelimiter_ = remain; + } + /* + stop parsing after delimiter is found + @param delimiter [in] string to stop to append list of delimiters + */ + void appendDelimiter(const std::string& delimiter) + { + delimiters_.push_back(delimiter); + } + /* + clear list of delimiters + */ + void clearDelimiterList() { delimiters_.clear(); } + /* + return the next position of delimiter between [0, argc] + @note return argc if delimiter is not set nor found + */ + int getNextPositionOfDelimiter() const { return nextDelimiter_; } + /* + parse (argc, argv) + @param argc [in] argc of main + @param argv [in] argv of main + @param startPos [in] start position of argc + @param progName [in] used instead of argv[0] + */ + bool parse(int argc, const char *const argv[], int startPos = 1, const char *progName = 0) + { + if (argc < 1 || startPos > argc) return false; + progName_ = getBaseName(progName ? progName : argv[startPos - 1]); + nextDelimiter_ = argc; + OptionError err; + for (int pos = startPos; pos < argc; pos++) { + if (inDelimiters(argv[pos])) { + nextDelimiter_ = pos + 1; + if (remainsAfterDelimiter_) { + for (int i = nextDelimiter_; i < argc; i++) { + remainsAfterDelimiter_->push_back(argv[i]); + } + } + break; + } + if (isOpt(argv[pos])) { + const std::string str = argv[pos] + 1; + if (helpOpt_ == str) { + usage(); + exit(0); + } + OptMap::const_iterator i = optMap_.find(str); + if (i == optMap_.end()) { + err.set(OptionError::BAD_OPT, pos); + goto ERR; + } + + Info& info = infoVec_[i->second]; + switch (info.mode) { + case N_is0: + if (!info.var.set("1")) { + err.set(OptionError::BAD_VALUE, pos); + goto ERR; + } + break; + case N_is1: + pos++; + if (pos == argc) { + err.set(OptionError::BAD_VALUE, pos) << (std::string("no value for -") + info.opt); + goto ERR; + } + if (!info.var.set(argv[pos])) { + err.set(OptionError::BAD_VALUE, pos) << (std::string(argv[pos]) + " for -" + info.opt); + goto ERR; + } + break; + case N_any: + default: + { + pos++; + int j = 0; + while (pos < argc && !isOpt(argv[pos])) { + if (!info.var.set(argv[pos])) { + err.set(OptionError::BAD_VALUE, pos) << (std::string(argv[pos]) + " for -" + info.opt) << j; + goto ERR; + } + pos++; + j++; + } + if (j > 0) { + pos--; + } else { + err.set(OptionError::NO_VALUE, pos) << (std::string("for -") + info.opt); + goto ERR; + } + } + break; + } + } else { + bool used = false; + for (size_t i = 0; i < paramVec_.size(); i++) { + Info& param = paramVec_[i]; + if (!param.var.isSet()) { + if (!param.var.set(argv[pos])) { + err.set(OptionError::BAD_VALUE, pos) << (std::string(argv[pos]) + " for " + param.opt); + goto ERR; + } + used = true; + break; + } + } + if (!used) { + if (paramMode_ == P_variable) { + remains_.var.set(argv[pos]); + } else { + err.set(OptionError::REDUNDANT_VAL, pos) << argv[pos]; + goto ERR; + } + } + } + } + // check whether must-opt is set + for (size_t i = 0; i < infoVec_.size(); i++) { + const Info& info = infoVec_[i]; + if (info.isMust && !info.var.isSet()) { + err.set(OptionError::OPT_IS_NECESSARY) << info.opt; + goto ERR; + } + } + // check whether param is set + for (size_t i = 0; i < paramVec_.size(); i++) { + const Info& param = paramVec_[i]; + if (param.isMust && !param.var.isSet()) { + err.set(OptionError::PARAM_IS_NECESSARY) << param.opt; + goto ERR; + } + } + // check whether remains is set + if (paramMode_ == P_variable && remains_.isMust && !remains_.var.isSet()) { + err.set(OptionError::PARAM_IS_NECESSARY) << remains_.opt; + goto ERR; + } + return true; + ERR: + assert(err.type); + printf("%s\n", err.what()); + return false; + } + /* + show desc at first in usage() + */ + void setDescription(const std::string& desc) + { + desc_ = desc; + } + /* + show command line after desc + don't put option message if not showOptUsage + */ + void setUsage(const std::string& usage, bool showOptUsage = false) + { + usage_ = usage; + showOptUsage_ = showOptUsage; + } + void usage() const + { + if (!desc_.empty()) printf("%s\n", desc_.c_str()); + if (usage_.empty()) { + printf("usage:%s", progName_.c_str()); + if (!infoVec_.empty()) printf(" [opt]"); + for (size_t i = 0; i < infoVec_.size(); i++) { + if (infoVec_[i].isMust) infoVec_[i].shortUsage(); + } + for (size_t i = 0; i < paramVec_.size(); i++) { + printf(" %s", paramVec_[i].opt.c_str()); + } + if (paramMode_ == P_variable) { + printf(" %s", remains_.opt.c_str()); + } + printf("\n"); + } else { + printf("%s\n", usage_.c_str()); + if (!showOptUsage_) return; + } + for (size_t i = 0; i < paramVec_.size(); i++) { + const Info& param = paramVec_[i]; + if (!param.help.empty()) printf(" %s %s\n", paramVec_[i].opt.c_str(), paramVec_[i].help.c_str()); + } + if (!remains_.help.empty()) printf(" %s %s\n", remains_.opt.c_str(), remains_.help.c_str()); + if (!helpOpt_.empty()) { + printf(" -%s %s\n", helpOpt_.c_str(), help_.c_str()); + } + for (size_t i = 0; i < infoVec_.size(); i++) { + infoVec_[i].usage(); + } + } + friend inline std::ostream& operator<<(std::ostream& os, const Option& self) + { + for (size_t i = 0; i < self.paramVec_.size(); i++) { + const Info& param = self.paramVec_[i]; + os << param.opt << '=' << param.var.toStr() << std::endl; + } + if (self.paramMode_ == P_variable) { + os << "remains=" << self.remains_.var.toStr() << std::endl; + } + for (size_t i = 0; i < self.infoVec_.size(); i++) { + os << self.infoVec_[i] << std::endl; + } + return os; + } + void put() const + { + std::cout << *this; + } + /* + whether pvar is set or not + */ + template<class T> + bool isSet(const T* pvar) const + { + const void *p = static_cast<const void*>(pvar); + for (size_t i = 0; i < paramVec_.size(); i++) { + const Info& v = paramVec_[i]; + if (v.get() == p) return v.isSet(); + } + if (remains_.get() == p) return remains_.isSet(); + for (size_t i = 0; i < infoVec_.size(); i++) { + const Info& v = infoVec_[i]; + if (v.get() == p) return v.isSet(); + } + throw cybozu::Exception("Option:isSet:no assigned var") << pvar; + } +}; + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/random_generator.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/random_generator.hpp new file mode 100644 index 000000000..23096989d --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/random_generator.hpp @@ -0,0 +1,139 @@ +#pragma once +/** + @file + @brief pseudrandom generator + @author MITSUNARI Shigeo(@herumi) + @license modified new BSD license + http://opensource.org/licenses/BSD-3-Clause +*/ + +#include <cybozu/exception.hpp> +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#include <wincrypt.h> +#ifdef _MSC_VER +#pragma comment (lib, "advapi32.lib") +#endif +#include <cybozu/critical_section.hpp> +#else +#include <sys/types.h> +#include <fcntl.h> +#endif + +namespace cybozu { + +class RandomGenerator { + RandomGenerator(const RandomGenerator&); + void operator=(const RandomGenerator&); +public: + uint32_t operator()() + { + return get32(); + } + uint32_t get32() + { + uint32_t ret; + read(&ret, 1); + return ret; + } + uint64_t get64() + { + uint64_t ret; + read(&ret, 1); + return ret; + } +#ifdef _WIN32 + RandomGenerator() + : prov_(0) + , pos_(bufSize) + { + DWORD flagTbl[] = { 0, CRYPT_NEWKEYSET }; + for (int i = 0; i < 2; i++) { + if (CryptAcquireContext(&prov_, NULL, NULL, PROV_RSA_FULL, flagTbl[i]) != 0) return; + } + throw cybozu::Exception("randomgenerator"); + } + void read_inner(void *buf, size_t byteSize) + { + if (CryptGenRandom(prov_, static_cast<DWORD>(byteSize), static_cast<BYTE*>(buf)) == 0) { + throw cybozu::Exception("randomgenerator:read") << byteSize; + } + } + ~RandomGenerator() + { + if (prov_) { + CryptReleaseContext(prov_, 0); + } + } + /* + fill buf[0..bufNum-1] with random data + @note bufNum is not byte size + */ + template<class T> + void read(T *buf, size_t bufNum) + { + cybozu::AutoLockCs al(cs_); + const size_t byteSize = sizeof(T) * bufNum; + if (byteSize > bufSize) { + read_inner(buf, byteSize); + } else { + if (pos_ + byteSize > bufSize) { + read_inner(buf_, bufSize); + pos_ = 0; + } + memcpy(buf, buf_ + pos_, byteSize); + pos_ += byteSize; + } + } +private: + HCRYPTPROV prov_; + static const size_t bufSize = 1024; + char buf_[bufSize]; + size_t pos_; + cybozu::CriticalSection cs_; +#else + RandomGenerator() + : fp_(::fopen("/dev/urandom", "rb")) + { + if (!fp_) throw cybozu::Exception("randomgenerator"); + } + ~RandomGenerator() + { + if (fp_) ::fclose(fp_); + } + /* + fill buf[0..bufNum-1] with random data + @note bufNum is not byte size + */ + template<class T> + void read(T *buf, size_t bufNum) + { + const size_t byteSize = sizeof(T) * bufNum; + if (::fread(buf, 1, (int)byteSize, fp_) != byteSize) { + throw cybozu::Exception("randomgenerator:read") << byteSize; + } + } +#endif +private: + FILE *fp_; +}; + +template<class T, class RG> +void shuffle(T* v, size_t n, RG& rg) +{ + if (n <= 1) return; + for (size_t i = 0; i < n - 1; i++) { + size_t r = i + size_t(rg.get64() % (n - i)); + using namespace std; + swap(v[i], v[r]); + } +} + +template<class V, class RG> +void shuffle(V& v, RG& rg) +{ + shuffle(v.data(), v.size(), rg); +} + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/serializer.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/serializer.hpp new file mode 100644 index 000000000..1e23c8f42 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/serializer.hpp @@ -0,0 +1,363 @@ +#pragma once +/** + @file + @brief serializer for vector, list, map and so on + + @author MITSUNARI Shigeo(@herumi) +*/ +#include <assert.h> +#include <cybozu/stream.hpp> + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4127) +#endif + +//#define CYBOZU_SERIALIZER_FIXED_SIZE_INTEGER + +namespace cybozu { + +namespace serializer_local { + +template<class T> +union ci { + T i; + uint8_t c[sizeof(T)]; +}; + +template<class S, void (S::*)(size_t)> +struct HasMemFunc { }; + +template<class T> +void dispatch_reserve(T& t, size_t size, int, HasMemFunc<T, &T::reserve>* = 0) +{ + t.reserve(size); +} + +template<class T> +void dispatch_reserve(T&, size_t, int*) +{ +} + +template<class T> +void reserve_if_exists(T& t, size_t size) +{ + dispatch_reserve(t, size, 0); +} + +} // serializer_local + +template<class InputStream, class T> +void loadRange(T *p, size_t num, InputStream& is) +{ + cybozu::read(p, num * sizeof(T), is); +} + +template<class OutputStream, class T> +void saveRange(OutputStream& os, const T *p, size_t num) +{ + cybozu::write(os, p, num * sizeof(T)); +} + +template<class InputStream, class T> +void loadPod(T& x, InputStream& is) +{ + serializer_local::ci<T> ci; + loadRange(ci.c, sizeof(ci.c), is); + x = ci.i; +} + +template<class OutputStream, class T> +void savePod(OutputStream& os, const T& x) +{ + serializer_local::ci<T> ci; + ci.i = x; + saveRange(os, ci.c, sizeof(ci.c)); +} + +template<class InputStream, class T> +void load(T& x, InputStream& is) +{ + x.load(is); +} + +template<class OutputStream, class T> +void save(OutputStream& os, const T& x) +{ + x.save(os); +} + +#define CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(type) \ +template<class InputStream>void load(type& x, InputStream& is) { loadPod(x, is); } \ +template<class OutputStream>void save(OutputStream& os, type x) { savePod(os, x); } + +CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(bool) +CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(char) +CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(short) +CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(unsigned char) +CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(unsigned short) +CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(wchar_t) + +CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(float) +CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(double) + +#ifdef CYBOZU_SERIALIZER_FIXED_SIZE_INTEGER + +#define CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER(type) CYBOZU_SERIALIZER_MAKE_SERIALIZER_F(type) + +#else + +namespace serializer_local { + +template<class S, class T> +bool isRecoverable(T x) +{ + return T(S(x)) == x; +} +/* + data structure H:D of integer x + H:header(1byte) + 0x80 ; D = 1 byte zero ext + 0x81 ; D = 2 byte zero ext + 0x82 ; D = 4 byte zero ext + 0x83 ; D = 8 byte zero ext + 0x84 ; D = 1 byte signed ext + 0x85 ; D = 2 byte signed ext + 0x86 ; D = 4 byte signed ext + 0x87 ; D = 8 byte signed ext + other; x = signed H, D = none +*/ +template<class OutputStream, class T> +void saveVariableInt(OutputStream& os, const T& x) +{ + if (isRecoverable<int8_t>(x)) { + uint8_t u8 = uint8_t(x); + if (unsigned(u8 - 0x80) <= 7) { + savePod(os, uint8_t(0x84)); + } + savePod(os, u8); + } else if (isRecoverable<uint8_t>(x)) { + savePod(os, uint8_t(0x80)); + savePod(os, uint8_t(x)); + } else if (isRecoverable<uint16_t>(x) || isRecoverable<int16_t>(x)) { + savePod(os, uint8_t(isRecoverable<uint16_t>(x) ? 0x81 : 0x85)); + savePod(os, uint16_t(x)); + } else if (isRecoverable<uint32_t>(x) || isRecoverable<int32_t>(x)) { + savePod(os, uint8_t(isRecoverable<uint32_t>(x) ? 0x82 : 0x86)); + savePod(os, uint32_t(x)); + } else { + assert(sizeof(T) == 8); + savePod(os, uint8_t(0x83)); + savePod(os, uint64_t(x)); + } +} + +template<class InputStream, class T> +void loadVariableInt(T& x, InputStream& is) +{ + uint8_t h; + loadPod(h, is); + if (h == 0x80) { + uint8_t v; + loadPod(v, is); + x = v; + } else if (h == 0x81) { + uint16_t v; + loadPod(v, is); + x = v; + } else if (h == 0x82) { + uint32_t v; + loadPod(v, is); + x = v; + } else if (h == 0x83) { + if (sizeof(T) == 4) throw cybozu::Exception("loadVariableInt:bad header") << h; + uint64_t v; + loadPod(v, is); + x = static_cast<T>(v); + } else if (h == 0x84) { + int8_t v; + loadPod(v, is); + x = v; + } else if (h == 0x85) { + int16_t v; + loadPod(v, is); + x = v; + } else if (h == 0x86) { + int32_t v; + loadPod(v, is); + x = v; + } else if (h == 0x87) { + if (sizeof(T) == 4) throw cybozu::Exception("loadVariableInt:bad header") << h; + int64_t v; + loadPod(v, is); + x = static_cast<T>(v); + } else { + x = static_cast<int8_t>(h); + } +} + +} // serializer_local + +#define CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER(type) \ +template<class InputStream>void load(type& x, InputStream& is) { serializer_local::loadVariableInt(x, is); } \ +template<class OutputStream>void save(OutputStream& os, type x) { serializer_local::saveVariableInt(os, x); } + +#endif + +CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER(int) +CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER(long) +CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER(long long) +CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER(unsigned int) +CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER(unsigned long) +CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER(unsigned long long) + +#undef CYBOZU_SERIALIZER_MAKE_INT_SERIALIZER +#undef CYBOZU_SERIALIZER_MAKE_UNT_SERIALIZER +#undef CYBOZU_SERIALIZER_MAKE_SERIALIZER_F +#undef CYBOZU_SERIALIZER_MAKE_SERIALIZER_V + +// only for std::vector<POD> +template<class V, class InputStream> +void loadPodVec(V& v, InputStream& is) +{ + size_t size; + load(size, is); + v.resize(size); + if (size > 0) loadRange(&v[0], size, is); +} + +// only for std::vector<POD> +template<class V, class OutputStream> +void savePodVec(OutputStream& os, const V& v) +{ + save(os, v.size()); + if (!v.empty()) saveRange(os, &v[0], v.size()); +} + +template<class InputStream> +void load(std::string& str, InputStream& is) +{ + loadPodVec(str, is); +} + +template<class OutputStream> +void save(OutputStream& os, const std::string& str) +{ + savePodVec(os, str); +} + +template<class OutputStream> +void save(OutputStream& os, const char *x) +{ + const size_t len = strlen(x); + save(os, len); + if (len > 0) saveRange(os, x, len); +} + + +// for vector, list +template<class InputStream, class T, class Alloc, template<class T_, class Alloc_>class Container> +void load(Container<T, Alloc>& x, InputStream& is) +{ + size_t size; + load(size, is); + serializer_local::reserve_if_exists(x, size); + for (size_t i = 0; i < size; i++) { + x.push_back(T()); + T& t = x.back(); + load(t, is); + } +} + +template<class OutputStream, class T, class Alloc, template<class T_, class Alloc_>class Container> +void save(OutputStream& os, const Container<T, Alloc>& x) +{ + typedef Container<T, Alloc> V; + save(os, x.size()); + for (typename V::const_iterator i = x.begin(), end = x.end(); i != end; ++i) { + save(os, *i); + } +} + +// for set +template<class InputStream, class K, class Pred, class Alloc, template<class K_, class Pred_, class Alloc_>class Container> +void load(Container<K, Pred, Alloc>& x, InputStream& is) +{ + size_t size; + load(size, is); + for (size_t i = 0; i < size; i++) { + K t; + load(t, is); + x.insert(t); + } +} + +template<class OutputStream, class K, class Pred, class Alloc, template<class K_, class Pred_, class Alloc_>class Container> +void save(OutputStream& os, const Container<K, Pred, Alloc>& x) +{ + typedef Container<K, Pred, Alloc> Set; + save(os, x.size()); + for (typename Set::const_iterator i = x.begin(), end = x.end(); i != end; ++i) { + save(os, *i); + } +} + +// for map +template<class InputStream, class K, class V, class Pred, class Alloc, template<class K_, class V_, class Pred_, class Alloc_>class Container> +void load(Container<K, V, Pred, Alloc>& x, InputStream& is) +{ + typedef Container<K, V, Pred, Alloc> Map; + size_t size; + load(size, is); + for (size_t i = 0; i < size; i++) { + std::pair<typename Map::key_type, typename Map::mapped_type> vt; + load(vt.first, is); + load(vt.second, is); + x.insert(vt); + } +} + +template<class OutputStream, class K, class V, class Pred, class Alloc, template<class K_, class V_, class Pred_, class Alloc_>class Container> +void save(OutputStream& os, const Container<K, V, Pred, Alloc>& x) +{ + typedef Container<K, V, Pred, Alloc> Map; + save(os, x.size()); + for (typename Map::const_iterator i = x.begin(), end = x.end(); i != end; ++i) { + save(os, i->first); + save(os, i->second); + } +} + +// unordered_map +template<class InputStream, class K, class V, class Hash, class Pred, class Alloc, template<class K_, class V_, class Hash_, class Pred_, class Alloc_>class Container> +void load(Container<K, V, Hash, Pred, Alloc>& x, InputStream& is) +{ + typedef Container<K, V, Hash, Pred, Alloc> Map; + size_t size; + load(size, is); +// x.reserve(size); // tr1::unordered_map may not have reserve + cybozu::serializer_local::reserve_if_exists(x, size); + for (size_t i = 0; i < size; i++) { + std::pair<typename Map::key_type, typename Map::mapped_type> vt; + load(vt.first, is); + load(vt.second, is); + x.insert(vt); + } +} + +template<class OutputStream, class K, class V, class Hash, class Pred, class Alloc, template<class K_, class V_, class Hash_, class Pred_, class Alloc_>class Container> +void save(OutputStream& os, const Container<K, V, Hash, Pred, Alloc>& x) +{ + typedef Container<K, V, Hash, Pred, Alloc> Map; + save(os, x.size()); + for (typename Map::const_iterator i = x.begin(), end = x.end(); i != end; ++i) { + save(os, i->first); + save(os, i->second); + } +} + +} // cybozu + +#ifdef _MSC_VER + #pragma warning(pop) +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/sha2.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/sha2.hpp new file mode 100644 index 000000000..97193849b --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/sha2.hpp @@ -0,0 +1,438 @@ +#pragma once +/** + @file + @brief SHA-256, SHA-512 class + @author MITSUNARI Shigeo(@herumi) + @license modified new BSD license + http://opensource.org/licenses/BSD-3-Clause +*/ +#include <cybozu/endian.hpp> +#ifndef CYBOZU_DONT_USE_STRING +#include <cybozu/itoa.hpp> +#include <string> +#endif +#include <memory.h> +#include <assert.h> + +namespace cybozu { + +namespace sha2_local { + +template<class T> +T min_(T x, T y) { return x < y ? x : y;; } + +#ifndef CYBOZU_DONT_USE_STRING +inline void uint32toHexStr(char *buf, const uint32_t *x, size_t n) +{ + for (size_t i = 0; i < n; i++) { + cybozu::itohex(buf + i * 8, 8, x[i], false); + } +} + +inline void uint64toHexStr(char *buf, const uint64_t *x, size_t n) +{ + for (size_t i = 0; i < n; i++) { + cybozu::itohex(buf + i * 16, 16, x[i], false); + } +} +#endif + +inline uint32_t rot32(uint32_t x, int s) +{ +#ifdef _MSC_VER + return _rotr(x, s); +#else + return (x >> s) | (x << (32 - s)); +#endif +} + +inline uint64_t rot64(uint64_t x, int s) +{ +#ifdef _MSC_VER + return _rotr64(x, s); +#else + return (x >> s) | (x << (64 - s)); +#endif +} + +} // cybozu::sha2_local + +class Sha256 { +private: + static const size_t blockSize_ = 64; + static const size_t hSize_ = 8; + uint64_t totalSize_; + size_t roundBufSize_; + char roundBuf_[blockSize_]; + uint32_t h_[hSize_]; + static const size_t outByteSize_ = hSize_ * sizeof(uint32_t); + const uint32_t *k_; + + /** + @param buf [in] buffer(64byte) + */ + void round(const char *buf) + { + using namespace sha2_local; + uint32_t w[64]; + for (int i = 0; i < 16; i++) { + w[i] = cybozu::Get32bitAsBE(&buf[i * 4]); + } + for (int i = 16 ; i < 64; i++) { + uint32_t t = w[i - 15]; + uint32_t s0 = rot32(t, 7) ^ rot32(t, 18) ^ (t >> 3); + t = w[i - 2]; + uint32_t s1 = rot32(t, 17) ^ rot32(t, 19) ^ (t >> 10); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + uint32_t a = h_[0]; + uint32_t b = h_[1]; + uint32_t c = h_[2]; + uint32_t d = h_[3]; + uint32_t e = h_[4]; + uint32_t f = h_[5]; + uint32_t g = h_[6]; + uint32_t h = h_[7]; + for (int i = 0; i < 64; i++) { + uint32_t s1 = rot32(e, 6) ^ rot32(e, 11) ^ rot32(e, 25); + uint32_t ch = g ^ (e & (f ^ g)); + uint32_t t1 = h + s1 + ch + k_[i] + w[i]; + uint32_t s0 = rot32(a, 2) ^ rot32(a, 13) ^ rot32(a, 22); + uint32_t maj = ((a | b) & c) | (a & b); + uint32_t t2 = s0 + maj; + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + h_[0] += a; + h_[1] += b; + h_[2] += c; + h_[3] += d; + h_[4] += e; + h_[5] += f; + h_[6] += g; + h_[7] += h; + totalSize_ += 64; + } + /* + final phase + */ + void term(const char *buf, size_t bufSize) + { + assert(bufSize < blockSize_); + const uint64_t totalSize = totalSize_ + bufSize; + + uint8_t last[blockSize_]; + memcpy(last, buf, bufSize); + memset(&last[bufSize], 0, blockSize_ - bufSize); + last[bufSize] = uint8_t(0x80); /* top bit = 1 */ + if (bufSize >= blockSize_ - 8) { + round(reinterpret_cast<const char*>(last)); + memset(last, 0, sizeof(last)); // clear stack + } + cybozu::Set32bitAsBE(&last[56], uint32_t(totalSize >> 29)); + cybozu::Set32bitAsBE(&last[60], uint32_t(totalSize * 8)); + round(reinterpret_cast<const char*>(last)); + } +public: + Sha256() + { + clear(); + } + Sha256(const void *buf, size_t bufSize) + { + clear(); + digest(buf, bufSize); + } + void clear() + { + static const uint32_t kTbl[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + k_ = kTbl; + totalSize_ = 0; + roundBufSize_ = 0; + h_[0] = 0x6a09e667; + h_[1] = 0xbb67ae85; + h_[2] = 0x3c6ef372; + h_[3] = 0xa54ff53a; + h_[4] = 0x510e527f; + h_[5] = 0x9b05688c; + h_[6] = 0x1f83d9ab; + h_[7] = 0x5be0cd19; + } + void update(const void *buf_, size_t bufSize) + { + const char *buf = reinterpret_cast<const char*>(buf_); + if (bufSize == 0) return; + if (roundBufSize_ > 0) { + size_t size = sha2_local::min_(blockSize_ - roundBufSize_, bufSize); + memcpy(roundBuf_ + roundBufSize_, buf, size); + roundBufSize_ += size; + buf += size; + bufSize -= size; + } + if (roundBufSize_ == blockSize_) { + round(roundBuf_); + roundBufSize_ = 0; + } + while (bufSize >= blockSize_) { + assert(roundBufSize_ == 0); + round(buf); + buf += blockSize_; + bufSize -= blockSize_; + } + if (bufSize > 0) { + assert(bufSize < blockSize_); + assert(roundBufSize_ == 0); + memcpy(roundBuf_, buf, bufSize); + roundBufSize_ = bufSize; + } + assert(roundBufSize_ < blockSize_); + } + void digest(const void *buf, size_t bufSize) + { + update(buf, bufSize); + term(roundBuf_, roundBufSize_); + } + size_t get(void *out) const + { + char *p = reinterpret_cast<char*>(out); + for (size_t i = 0; i < hSize_; i++) { + cybozu::Set32bitAsBE(&p[i * sizeof(h_[0])], h_[i]); + } + return outByteSize_; + } +#ifndef CYBOZU_DONT_USE_STRING + void update(const std::string& buf) + { + update(buf.c_str(), buf.size()); + } + void digest(const std::string& str = "") + { + digest(str.c_str(), str.size()); + } + std::string get() const + { + char out[outByteSize_]; + get(out); + return std::string(out, sizeof(out)); + } + std::string toHexStr() const + { + char buf[outByteSize_ * 2]; + sha2_local::uint32toHexStr(buf, h_, hSize_); + return std::string(buf, sizeof(buf)); + } +#endif +}; + +class Sha512 { +private: + static const size_t blockSize_ = 128; + static const size_t hSize_ = 8; + uint64_t totalSize_; + size_t roundBufSize_; + char roundBuf_[blockSize_]; + uint64_t h_[hSize_]; + static const size_t outByteSize_ = hSize_ * sizeof(uint64_t); + const uint64_t *k_; + + template<size_t i0, size_t i1, size_t i2, size_t i3, size_t i4, size_t i5, size_t i6, size_t i7> + void round1(uint64_t *S, const uint64_t *w, size_t i) + { + using namespace sha2_local; + uint64_t& a = S[i0]; + uint64_t& b = S[i1]; + uint64_t& c = S[i2]; + uint64_t& d = S[i3]; + uint64_t& e = S[i4]; + uint64_t& f = S[i5]; + uint64_t& g = S[i6]; + uint64_t& h = S[i7]; + + uint64_t s1 = rot64(e, 14) ^ rot64(e, 18) ^ rot64(e, 41); + uint64_t ch = g ^ (e & (f ^ g)); + uint64_t t0 = h + s1 + ch + k_[i] + w[i]; + uint64_t s0 = rot64(a, 28) ^ rot64(a, 34) ^ rot64(a, 39); + uint64_t maj = ((a | b) & c) | (a & b); + uint64_t t1 = s0 + maj; + d += t0; + h = t0 + t1; + } + /** + @param buf [in] buffer(64byte) + */ + void round(const char *buf) + { + using namespace sha2_local; + uint64_t w[80]; + for (int i = 0; i < 16; i++) { + w[i] = cybozu::Get64bitAsBE(&buf[i * 8]); + } + for (int i = 16 ; i < 80; i++) { + uint64_t t = w[i - 15]; + uint64_t s0 = rot64(t, 1) ^ rot64(t, 8) ^ (t >> 7); + t = w[i - 2]; + uint64_t s1 = rot64(t, 19) ^ rot64(t, 61) ^ (t >> 6); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + uint64_t s[8]; + for (int i = 0; i < 8; i++) { + s[i] = h_[i]; + } + for (int i = 0; i < 80; i += 8) { + round1<0, 1, 2, 3, 4, 5, 6, 7>(s, w, i + 0); + round1<7, 0, 1, 2, 3, 4, 5, 6>(s, w, i + 1); + round1<6, 7, 0, 1, 2, 3, 4, 5>(s, w, i + 2); + round1<5, 6, 7, 0, 1, 2, 3, 4>(s, w, i + 3); + round1<4, 5, 6, 7, 0, 1, 2, 3>(s, w, i + 4); + round1<3, 4, 5, 6, 7, 0, 1, 2>(s, w, i + 5); + round1<2, 3, 4, 5, 6, 7, 0, 1>(s, w, i + 6); + round1<1, 2, 3, 4, 5, 6, 7, 0>(s, w, i + 7); + } + for (int i = 0; i < 8; i++) { + h_[i] += s[i]; + } + totalSize_ += blockSize_; + } + /* + final phase + */ + void term(const char *buf, size_t bufSize) + { + assert(bufSize < blockSize_); + const uint64_t totalSize = totalSize_ + bufSize; + + uint8_t last[blockSize_]; + memcpy(last, buf, bufSize); + memset(&last[bufSize], 0, blockSize_ - bufSize); + last[bufSize] = uint8_t(0x80); /* top bit = 1 */ + if (bufSize >= blockSize_ - 16) { + round(reinterpret_cast<const char*>(last)); + memset(last, 0, sizeof(last)); // clear stack + } + cybozu::Set64bitAsBE(&last[blockSize_ - 8], totalSize * 8); + round(reinterpret_cast<const char*>(last)); + } +public: + Sha512() + { + clear(); + } + Sha512(const void *buf, size_t bufSize) + { + clear(); + digest(buf, bufSize); + } + void clear() + { + static const uint64_t kTbl[] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, + 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, + 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, + 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, + 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, + 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL + }; + k_ = kTbl; + totalSize_ = 0; + roundBufSize_ = 0; + h_[0] = 0x6a09e667f3bcc908ull; + h_[1] = 0xbb67ae8584caa73bull; + h_[2] = 0x3c6ef372fe94f82bull; + h_[3] = 0xa54ff53a5f1d36f1ull; + h_[4] = 0x510e527fade682d1ull; + h_[5] = 0x9b05688c2b3e6c1full; + h_[6] = 0x1f83d9abfb41bd6bull; + h_[7] = 0x5be0cd19137e2179ull; + } + void update(const void *buf_, size_t bufSize) + { + const char *buf = reinterpret_cast<const char*>(buf_); + if (bufSize == 0) return; + if (roundBufSize_ > 0) { + size_t size = sha2_local::min_(blockSize_ - roundBufSize_, bufSize); + memcpy(roundBuf_ + roundBufSize_, buf, size); + roundBufSize_ += size; + buf += size; + bufSize -= size; + } + if (roundBufSize_ == blockSize_) { + round(roundBuf_); + roundBufSize_ = 0; + } + while (bufSize >= blockSize_) { + assert(roundBufSize_ == 0); + round(buf); + buf += blockSize_; + bufSize -= blockSize_; + } + if (bufSize > 0) { + assert(bufSize < blockSize_); + assert(roundBufSize_ == 0); + memcpy(roundBuf_, buf, bufSize); + roundBufSize_ = bufSize; + } + assert(roundBufSize_ < blockSize_); + } + void digest(const void *buf, size_t bufSize) + { + update(buf, bufSize); + term(roundBuf_, roundBufSize_); + } + size_t get(void *out) const + { + char *p = reinterpret_cast<char*>(out); + for (size_t i = 0; i < hSize_; i++) { + cybozu::Set64bitAsBE(&p[i * sizeof(h_[0])], h_[i]); + } + return outByteSize_; + } +#ifndef CYBOZU_DONT_USE_STRING + void digest(const std::string& str = "") + { + digest(str.c_str(), str.size()); + } + void update(const std::string& buf) + { + update(buf.c_str(), buf.size()); + } + std::string get() const + { + char out[outByteSize_]; + get(out); + return std::string(out, sizeof(out)); + } + std::string toHexStr() const + { + char buf[outByteSize_ * 2]; + sha2_local::uint64toHexStr(buf, h_, hSize_); + return std::string(buf, sizeof(buf)); + } +#endif +}; + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/stream.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/stream.hpp new file mode 100644 index 000000000..bc110bdb0 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/stream.hpp @@ -0,0 +1,267 @@ +#pragma once +/** + @file + @brief stream and line stream class + + @author MITSUNARI Shigeo(@herumi) +*/ +#ifndef CYBOZU_DONT_USE_STRING +#include <string> +#include <iosfwd> +#endif +#include <cybozu/exception.hpp> +#include <memory.h> + +namespace cybozu { + +namespace stream_local { + +template <typename From, typename To> +struct is_convertible { + typedef char yes; + typedef int no; + + static no test(...); + static yes test(const To*); + static const bool value = sizeof(test(static_cast<const From*>(0))) == sizeof(yes); +}; + +template <bool b, class T = void> +struct enable_if { typedef T type; }; + +template <class T> +struct enable_if<false, T> {}; + +#ifndef CYBOZU_DONT_USE_STRING +/* specialization for istream */ +template<class InputStream> +size_t readSome_inner(void *buf, size_t size, InputStream& is, typename enable_if<is_convertible<InputStream, std::istream>::value>::type* = 0) +{ + if (size > 0x7fffffff) size = 0x7fffffff; + is.read(static_cast<char *>(buf), size); + const int64_t readSize = is.gcount(); + if (readSize < 0) return 0; + if (size == 1 && readSize == 0) is.clear(); + return static_cast<size_t>(readSize); +} + +/* generic version for size_t readSome(void *, size_t) */ +template<class InputStream> +size_t readSome_inner(void *buf, size_t size, InputStream& is, typename enable_if<!is_convertible<InputStream, std::istream>::value>::type* = 0) +{ + return is.readSome(buf, size); +} +#else +template<class InputStream> +size_t readSome_inner(void *buf, size_t size, InputStream& is) +{ + return is.readSome(buf, size); +} +#endif + +#ifndef CYBOZU_DONT_USE_EXCEPTION +/* specialization for ostream */ +template<class OutputStream> +void writeSub(OutputStream& os, const void *buf, size_t size, typename enable_if<is_convertible<OutputStream, std::ostream>::value>::type* = 0) +{ + if (!os.write(static_cast<const char *>(buf), size)) throw cybozu::Exception("stream:writeSub") << size; +} +#endif + +#ifndef CYBOZU_DONT_USE_STRING +/* generic version for void write(const void*, size_t), which writes all data */ +template<class OutputStream> +void writeSub(OutputStream& os, const void *buf, size_t size, typename enable_if<!is_convertible<OutputStream, std::ostream>::value>::type* = 0) +{ + os.write(buf, size); +} + +template<class OutputStream> +void writeSub(bool *pb, OutputStream& os, const void *buf, size_t size, typename enable_if<is_convertible<OutputStream, std::ostream>::value>::type* = 0) +{ + *pb = !!os.write(static_cast<const char *>(buf), size); +} + +/* generic version for void write(const void*, size_t), which writes all data */ +template<class OutputStream> +void writeSub(bool *pb, OutputStream& os, const void *buf, size_t size, typename enable_if<!is_convertible<OutputStream, std::ostream>::value>::type* = 0) +{ + os.write(pb, buf, size); +} +#else +template<class OutputStream> +void writeSub(bool *pb, OutputStream& os, const void *buf, size_t size) +{ + os.write(pb, buf, size); +} +#endif + +} // stream_local + +/* + make a specializaiton of class to use new InputStream, OutputStream +*/ +template<class InputStream> +struct InputStreamTag { + static size_t readSome(void *buf, size_t size, InputStream& is) + { + return stream_local::readSome_inner<InputStream>(buf, size, is); + } + static bool readChar(char *c, InputStream& is) + { + return readSome(c, 1, is) == 1; + } +}; + +template<class OutputStream> +struct OutputStreamTag { + static void write(OutputStream& os, const void *buf, size_t size) + { + stream_local::writeSub<OutputStream>(os, buf, size); + } +}; + +class MemoryInputStream { + const char *p_; + size_t size_; + size_t pos; +public: + MemoryInputStream(const void *p, size_t size) : p_(static_cast<const char *>(p)), size_(size), pos(0) {} + size_t readSome(void *buf, size_t size) + { + if (size > size_ - pos) size = size_ - pos; + memcpy(buf, p_ + pos, size); + pos += size; + return size; + } + size_t getPos() const { return pos; } +}; + +class MemoryOutputStream { + char *p_; + size_t size_; + size_t pos; +public: + MemoryOutputStream(void *p, size_t size) : p_(static_cast<char *>(p)), size_(size), pos(0) {} + void write(bool *pb, const void *buf, size_t size) + { + if (size > size_ - pos) { + *pb = false; + return; + } + memcpy(p_ + pos, buf, size); + pos += size; + *pb = true; + } +#ifndef CYBOZU_DONT_USE_EXCEPTION + void write(const void *buf, size_t size) + { + bool b; + write(&b, buf, size); + if (!b) throw cybozu::Exception("MemoryOutputStream:write") << size << size_ << pos; + } +#endif + size_t getPos() const { return pos; } +}; + +#ifndef CYBOZU_DONT_USE_STRING +class StringInputStream { + const std::string& str_; + size_t pos; + StringInputStream(const StringInputStream&); + void operator=(const StringInputStream&); +public: + explicit StringInputStream(const std::string& str) : str_(str), pos(0) {} + size_t readSome(void *buf, size_t size) + { + const size_t remainSize = str_.size() - pos; + if (size > remainSize) size = remainSize; + memcpy(buf, &str_[pos], size); + pos += size; + return size; + } + size_t getPos() const { return pos; } +}; + +class StringOutputStream { + std::string& str_; + StringOutputStream(const StringOutputStream&); + void operator=(const StringOutputStream&); +public: + explicit StringOutputStream(std::string& str) : str_(str) {} + void write(bool *pb, const void *buf, size_t size) + { + str_.append(static_cast<const char *>(buf), size); + *pb = true; + } + void write(const void *buf, size_t size) + { + str_.append(static_cast<const char *>(buf), size); + } + size_t getPos() const { return str_.size(); } +}; +#endif + +template<class InputStream> +size_t readSome(void *buf, size_t size, InputStream& is) +{ + return stream_local::readSome_inner(buf, size, is); +} + +template<class OutputStream> +void write(OutputStream& os, const void *buf, size_t size) +{ + stream_local::writeSub(os, buf, size); +} + +template<class OutputStream> +void write(bool *pb, OutputStream& os, const void *buf, size_t size) +{ + stream_local::writeSub(pb, os, buf, size); +} + +template<typename InputStream> +void read(bool *pb, void *buf, size_t size, InputStream& is) +{ + char *p = static_cast<char*>(buf); + while (size > 0) { + size_t readSize = cybozu::readSome(p, size, is); + if (readSize == 0) { + *pb = false; + return; + } + p += readSize; + size -= readSize; + } + *pb = true; +} + +#ifndef CYBOZU_DONT_USE_EXCEPTION +template<typename InputStream> +void read(void *buf, size_t size, InputStream& is) +{ + bool b; + read(&b, buf, size, is); + if (!b) throw cybozu::Exception("stream:read"); +} +#endif + +template<class InputStream> +bool readChar(char *c, InputStream& is) +{ + return readSome(c, 1, is) == 1; +} + +template<class OutputStream> +void writeChar(OutputStream& os, char c) +{ + cybozu::write(os, &c, 1); +} + +template<class OutputStream> +void writeChar(bool *pb, OutputStream& os, char c) +{ + cybozu::write(pb, os, &c, 1); +} + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/test.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/test.hpp new file mode 100644 index 000000000..7dfffab96 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/test.hpp @@ -0,0 +1,373 @@ +#pragma once +/** + @file + @brief unit test class + + @author MITSUNARI Shigeo(@herumi) +*/ + +#include <stdio.h> +#include <string.h> +#include <string> +#include <list> +#include <iostream> +#include <utility> +#if defined(_MSC_VER) && (MSC_VER <= 1500) + #include <cybozu/inttype.hpp> +#else + #include <stdint.h> +#endif + +namespace cybozu { namespace test { + +class AutoRun { + typedef void (*Func)(); + typedef std::list<std::pair<const char*, Func> > UnitTestList; +public: + AutoRun() + : init_(0) + , term_(0) + , okCount_(0) + , ngCount_(0) + , exceptionCount_(0) + { + } + void setup(Func init, Func term) + { + init_ = init; + term_ = term; + } + void append(const char *name, Func func) + { + list_.push_back(std::make_pair(name, func)); + } + void set(bool isOK) + { + if (isOK) { + okCount_++; + } else { + ngCount_++; + } + } + std::string getBaseName(const std::string& name) const + { +#ifdef _WIN32 + const char sep = '\\'; +#else + const char sep = '/'; +#endif + size_t pos = name.find_last_of(sep); + std::string ret = name.substr(pos + 1); + pos = ret.find('.'); + return ret.substr(0, pos); + } + int run(int, char *argv[]) + { + std::string msg; + try { + if (init_) init_(); + for (UnitTestList::const_iterator i = list_.begin(), ie = list_.end(); i != ie; ++i) { + std::cout << "ctest:module=" << i->first << std::endl; + try { + (i->second)(); + } catch (std::exception& e) { + exceptionCount_++; + std::cout << "ctest: " << i->first << " is stopped by exception " << e.what() << std::endl; + } catch (...) { + exceptionCount_++; + std::cout << "ctest: " << i->first << " is stopped by unknown exception" << std::endl; + } + } + if (term_) term_(); + } catch (std::exception& e) { + msg = std::string("ctest:err:") + e.what(); + } catch (...) { + msg = "ctest:err: catch unknown exception"; + } + fflush(stdout); + if (msg.empty()) { + int err = ngCount_ + exceptionCount_; + int total = okCount_ + err; + std::cout << "ctest:name=" << getBaseName(*argv) + << ", module=" << list_.size() + << ", total=" << total + << ", ok=" << okCount_ + << ", ng=" << ngCount_ + << ", exception=" << exceptionCount_ << std::endl; + return err > 0 ? 1 : 0; + } else { + std::cout << msg << std::endl; + return 1; + } + } + static inline AutoRun& getInstance() + { + static AutoRun instance; + return instance; + } +private: + Func init_; + Func term_; + int okCount_; + int ngCount_; + int exceptionCount_; + UnitTestList list_; +}; + +static AutoRun& autoRun = AutoRun::getInstance(); + +inline void test(bool ret, const std::string& msg, const std::string& param, const char *file, int line) +{ + autoRun.set(ret); + if (!ret) { + printf("%s(%d):ctest:%s(%s);\n", file, line, msg.c_str(), param.c_str()); + } +} + +template<typename T, typename U> +bool isEqual(const T& lhs, const U& rhs) +{ + return lhs == rhs; +} + +// avoid warning of comparision of integers of different signs +inline bool isEqual(size_t lhs, int rhs) +{ + return lhs == size_t(rhs); +} +inline bool isEqual(int lhs, size_t rhs) +{ + return size_t(lhs) == rhs; +} +inline bool isEqual(const char *lhs, const char *rhs) +{ + return strcmp(lhs, rhs) == 0; +} +inline bool isEqual(char *lhs, const char *rhs) +{ + return strcmp(lhs, rhs) == 0; +} +inline bool isEqual(const char *lhs, char *rhs) +{ + return strcmp(lhs, rhs) == 0; +} +inline bool isEqual(char *lhs, char *rhs) +{ + return strcmp(lhs, rhs) == 0; +} +// avoid to compare float directly +inline bool isEqual(float lhs, float rhs) +{ + union fi { + float f; + uint32_t i; + } lfi, rfi; + lfi.f = lhs; + rfi.f = rhs; + return lfi.i == rfi.i; +} +// avoid to compare double directly +inline bool isEqual(double lhs, double rhs) +{ + union di { + double d; + uint64_t i; + } ldi, rdi; + ldi.d = lhs; + rdi.d = rhs; + return ldi.i == rdi.i; +} + +} } // cybozu::test + +#ifndef CYBOZU_TEST_DISABLE_AUTO_RUN +int main(int argc, char *argv[]) +{ + return cybozu::test::autoRun.run(argc, argv); +} +#endif + +/** + alert if !x + @param x [in] +*/ +#define CYBOZU_TEST_ASSERT(x) cybozu::test::test(!!(x), "CYBOZU_TEST_ASSERT", #x, __FILE__, __LINE__) + +/** + alert if x != y + @param x [in] + @param y [in] +*/ +#define CYBOZU_TEST_EQUAL(x, y) { \ + bool _cybozu_eq = cybozu::test::isEqual(x, y); \ + cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL", #x ", " #y, __FILE__, __LINE__); \ + if (!_cybozu_eq) { \ + std::cout << "ctest: lhs=" << (x) << std::endl; \ + std::cout << "ctest: rhs=" << (y) << std::endl; \ + } \ +} +/** + alert if fabs(x, y) >= eps + @param x [in] + @param y [in] +*/ +#define CYBOZU_TEST_NEAR(x, y, eps) { \ + bool _cybozu_isNear = fabs((x) - (y)) < eps; \ + cybozu::test::test(_cybozu_isNear, "CYBOZU_TEST_NEAR", #x ", " #y, __FILE__, __LINE__); \ + if (!_cybozu_isNear) { \ + std::cout << "ctest: lhs=" << (x) << std::endl; \ + std::cout << "ctest: rhs=" << (y) << std::endl; \ + } \ +} + +#define CYBOZU_TEST_EQUAL_POINTER(x, y) { \ + bool _cybozu_eq = x == y; \ + cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL_POINTER", #x ", " #y, __FILE__, __LINE__); \ + if (!_cybozu_eq) { \ + std::cout << "ctest: lhs=" << static_cast<const void*>(x) << std::endl; \ + std::cout << "ctest: rhs=" << static_cast<const void*>(y) << std::endl; \ + } \ +} +/** + alert if x[] != y[] + @param x [in] + @param y [in] + @param n [in] +*/ +#define CYBOZU_TEST_EQUAL_ARRAY(x, y, n) { \ + for (size_t _cybozu_test_i = 0, _cybozu_ie = (size_t)(n); _cybozu_test_i < _cybozu_ie; _cybozu_test_i++) { \ + bool _cybozu_eq = cybozu::test::isEqual((x)[_cybozu_test_i], (y)[_cybozu_test_i]); \ + cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL_ARRAY", #x ", " #y ", " #n, __FILE__, __LINE__); \ + if (!_cybozu_eq) { \ + std::cout << "ctest: i=" << _cybozu_test_i << std::endl; \ + std::cout << "ctest: lhs=" << (x)[_cybozu_test_i] << std::endl; \ + std::cout << "ctest: rhs=" << (y)[_cybozu_test_i] << std::endl; \ + } \ + } \ +} + +/** + always alert + @param msg [in] +*/ +#define CYBOZU_TEST_FAIL(msg) cybozu::test::test(false, "CYBOZU_TEST_FAIL", msg, __FILE__, __LINE__) + +/** + verify message in exception +*/ +#define CYBOZU_TEST_EXCEPTION_MESSAGE(statement, Exception, msg) \ +{ \ + int _cybozu_ret = 0; \ + std::string _cybozu_errMsg; \ + try { \ + statement; \ + _cybozu_ret = 1; \ + } catch (const Exception& _cybozu_e) { \ + _cybozu_errMsg = _cybozu_e.what(); \ + if (_cybozu_errMsg.find(msg) == std::string::npos) { \ + _cybozu_ret = 2; \ + } \ + } catch (...) { \ + _cybozu_ret = 3; \ + } \ + if (_cybozu_ret) { \ + cybozu::test::test(false, "CYBOZU_TEST_EXCEPTION_MESSAGE", #statement ", " #Exception ", " #msg, __FILE__, __LINE__); \ + if (_cybozu_ret == 1) { \ + std::cout << "ctest: no exception" << std::endl; \ + } else if (_cybozu_ret == 2) { \ + std::cout << "ctest: bad exception msg:" << _cybozu_errMsg << std::endl; \ + } else { \ + std::cout << "ctest: unexpected exception" << std::endl; \ + } \ + } else { \ + cybozu::test::autoRun.set(true); \ + } \ +} + +#define CYBOZU_TEST_EXCEPTION(statement, Exception) \ +{ \ + int _cybozu_ret = 0; \ + try { \ + statement; \ + _cybozu_ret = 1; \ + } catch (const Exception&) { \ + } catch (...) { \ + _cybozu_ret = 2; \ + } \ + if (_cybozu_ret) { \ + cybozu::test::test(false, "CYBOZU_TEST_EXCEPTION", #statement ", " #Exception, __FILE__, __LINE__); \ + if (_cybozu_ret == 1) { \ + std::cout << "ctest: no exception" << std::endl; \ + } else { \ + std::cout << "ctest: unexpected exception" << std::endl; \ + } \ + } else { \ + cybozu::test::autoRun.set(true); \ + } \ +} + +/** + verify statement does not throw +*/ +#define CYBOZU_TEST_NO_EXCEPTION(statement) \ +try { \ + statement; \ + cybozu::test::autoRun.set(true); \ +} catch (...) { \ + cybozu::test::test(false, "CYBOZU_TEST_NO_EXCEPTION", #statement, __FILE__, __LINE__); \ +} + +/** + append auto unit test + @param name [in] module name +*/ +#define CYBOZU_TEST_AUTO(name) \ +void cybozu_test_ ## name(); \ +struct cybozu_test_local_ ## name { \ + cybozu_test_local_ ## name() \ + { \ + cybozu::test::autoRun.append(#name, cybozu_test_ ## name); \ + } \ +} cybozu_test_local_instance_ ## name; \ +void cybozu_test_ ## name() + +/** + append auto unit test with fixture + @param name [in] module name +*/ +#define CYBOZU_TEST_AUTO_WITH_FIXTURE(name, Fixture) \ +void cybozu_test_ ## name(); \ +void cybozu_test_real_ ## name() \ +{ \ + Fixture f; \ + cybozu_test_ ## name(); \ +} \ +struct cybozu_test_local_ ## name { \ + cybozu_test_local_ ## name() \ + { \ + cybozu::test::autoRun.append(#name, cybozu_test_real_ ## name); \ + } \ +} cybozu_test_local_instance_ ## name; \ +void cybozu_test_ ## name() + +/** + setup fixture + @param Fixture [in] class name of fixture + @note cstr of Fixture is called before test and dstr of Fixture is called after test +*/ +#define CYBOZU_TEST_SETUP_FIXTURE(Fixture) \ +Fixture *cybozu_test_local_fixture; \ +void cybozu_test_local_init() \ +{ \ + cybozu_test_local_fixture = new Fixture(); \ +} \ +void cybozu_test_local_term() \ +{ \ + delete cybozu_test_local_fixture; \ +} \ +struct cybozu_test_local_fixture_setup_ { \ + cybozu_test_local_fixture_setup_() \ + { \ + cybozu::test::autoRun.setup(cybozu_test_local_init, cybozu_test_local_term); \ + } \ +} cybozu_test_local_fixture_setup_instance_; diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/unordered_map.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/unordered_map.hpp new file mode 100644 index 000000000..89f8f8774 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/unordered_map.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include <cybozu/inttype.hpp> + +#ifdef CYBOZU_USE_BOOST + #include <boost/unordered_map.hpp> +#elif (CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11) || (defined __APPLE__) + #include <unordered_map> +#elif (CYBOZU_CPP_VERSION == CYBOZU_CPP_VERSION_TR1) + #include <list> + #include <tr1/unordered_map> +#endif + diff --git a/vendor/github.com/dexon-foundation/mcl/include/cybozu/xorshift.hpp b/vendor/github.com/dexon-foundation/mcl/include/cybozu/xorshift.hpp new file mode 100644 index 000000000..69edaa939 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/cybozu/xorshift.hpp @@ -0,0 +1,172 @@ +#pragma once +/** + @file + @brief XorShift + + @author MITSUNARI Shigeo(@herumi) + @author MITSUNARI Shigeo +*/ +#include <cybozu/inttype.hpp> + +namespace cybozu { + +class XorShift { + uint32_t x_, y_, z_, w_; +public: + explicit XorShift(uint32_t x = 0, uint32_t y = 0, uint32_t z = 0, uint32_t w = 0) + { + init(x, y, z, w); + } + void init(uint32_t x = 0, uint32_t y = 0, uint32_t z = 0, uint32_t w = 0) + { + x_ = x ? x : 123456789; + y_ = y ? y : 362436069; + z_ = z ? z : 521288629; + w_ = w ? w : 88675123; + } + uint32_t get32() + { + unsigned int t = x_ ^ (x_ << 11); + x_ = y_; y_ = z_; z_ = w_; + return w_ = (w_ ^ (w_ >> 19)) ^ (t ^ (t >> 8)); + } + uint32_t operator()() { return get32(); } + uint64_t get64() + { + uint32_t a = get32(); + uint32_t b = get32(); + return (uint64_t(a) << 32) | b; + } + template<class T> + void read(T *x, size_t n) + { + const size_t size = sizeof(T) * n; + uint8_t *p8 = static_cast<uint8_t*>(x); + for (size_t i = 0; i < size; i++) { + p8[i] = static_cast<uint8_t>(get32()); + } + } + void read(uint32_t *x, size_t n) + { + for (size_t i = 0; i < n; i++) { + x[i] = get32(); + } + } + void read(uint64_t *x, size_t n) + { + for (size_t i = 0; i < n; i++) { + x[i] = get64(); + } + } +}; + +// see http://xorshift.di.unimi.it/xorshift128plus.c +class XorShift128Plus { + uint64_t s_[2]; + static const uint64_t seed0 = 123456789; + static const uint64_t seed1 = 987654321; +public: + explicit XorShift128Plus(uint64_t s0 = seed0, uint64_t s1 = seed1) + { + init(s0, s1); + } + void init(uint64_t s0 = seed0, uint64_t s1 = seed1) + { + s_[0] = s0; + s_[1] = s1; + } + uint32_t get32() + { + return static_cast<uint32_t>(get64()); + } + uint64_t operator()() { return get64(); } + uint64_t get64() + { + uint64_t s1 = s_[0]; + const uint64_t s0 = s_[1]; + s_[0] = s0; + s1 ^= s1 << 23; + s_[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); + return s_[1] + s0; + } + template<class T> + void read(T *x, size_t n) + { + const size_t size = sizeof(T) * n; + uint8_t *p8 = static_cast<uint8_t*>(x); + for (size_t i = 0; i < size; i++) { + p8[i] = static_cast<uint8_t>(get32()); + } + } + void read(uint32_t *x, size_t n) + { + for (size_t i = 0; i < n; i++) { + x[i] = get32(); + } + } + void read(uint64_t *x, size_t n) + { + for (size_t i = 0; i < n; i++) { + x[i] = get64(); + } + } +}; + +// see http://xoroshiro.di.unimi.it/xoroshiro128plus.c +class Xoroshiro128Plus { + uint64_t s_[2]; + static const uint64_t seed0 = 123456789; + static const uint64_t seed1 = 987654321; + uint64_t rotl(uint64_t x, unsigned int k) const + { + return (x << k) | (x >> (64 - k)); + } +public: + explicit Xoroshiro128Plus(uint64_t s0 = seed0, uint64_t s1 = seed1) + { + init(s0, s1); + } + void init(uint64_t s0 = seed0, uint64_t s1 = seed1) + { + s_[0] = s0; + s_[1] = s1; + } + uint32_t get32() + { + return static_cast<uint32_t>(get64()); + } + uint64_t operator()() { return get64(); } + uint64_t get64() + { + uint64_t s0 = s_[0]; + uint64_t s1 = s_[1]; + uint64_t result = s0 + s1; + s1 ^= s0; + s_[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); + s_[1] = rotl(s1, 36); + return result; + } + template<class T> + void read(T *x, size_t n) + { + const size_t size = sizeof(T) * n; + uint8_t *p8 = static_cast<uint8_t*>(x); + for (size_t i = 0; i < size; i++) { + p8[i] = static_cast<uint8_t>(get32()); + } + } + void read(uint32_t *x, size_t n) + { + for (size_t i = 0; i < n; i++) { + x[i] = get32(); + } + } + void read(uint64_t *x, size_t n) + { + for (size_t i = 0; i < n; i++) { + x[i] = get64(); + } + } +}; + +} // cybozu diff --git a/vendor/github.com/dexon-foundation/mcl/include/mcl/aggregate_sig.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/aggregate_sig.hpp new file mode 100644 index 000000000..f31405705 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/ahe.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/ahe.hpp new file mode 100644 index 000000000..239319d0d --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/array.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/array.hpp new file mode 100644 index 000000000..84c5f3765 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/array.hpp @@ -0,0 +1,146 @@ +#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> + +namespace mcl { + +template<class T> +class Array { + T *p_; + size_t n_; + Array(const Array&); + void operator=(const Array&); + 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_); + } + 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/dexon-foundation/mcl/include/mcl/bls12_381.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/bls12_381.hpp new file mode 100644 index 000000000..316e142af --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/bn.h b/vendor/github.com/dexon-foundation/mcl/include/mcl/bn.h new file mode 100644 index 000000000..9c78f92f1 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/bn.h @@ -0,0 +1,368 @@ +#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; + +#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; + +#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 +}; + +/* + 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 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); + +/* + 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); + +/* + 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); + +/* + 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); + +// set zero +MCLBN_DLL_API void mclBnFr_clear(mclBnFr *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); + +// mask buf with (1 << (bitLen(r) - 1)) - 1 if buf >= r +MCLBN_DLL_API int mclBnFr_setLittleEndian(mclBnFr *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); + +#ifndef MCL_DONT_USE_CSRPNG +// return 0 if success +MCLBN_DLL_API int mclBnFr_setByCSPRNG(mclBnFr *x); +#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 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 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); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/mcl/bn.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/bn.hpp new file mode 100644 index 000000000..8e9a9c652 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/bn.hpp @@ -0,0 +1,2194 @@ +#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 { + Fp c1_; // sqrt(-3) + Fp c2_; // (-1 + sqrt(-3)) / 2 + mpz_class z_; + mpz_class cofactor_; + bool isBN_; + 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; + } + void init(const mpz_class& cofactor, const mpz_class &z, bool isBN, int curveType = -1) + { + isBN_ = isBN; + if (isBN_) { + initBN(cofactor, z, curveType); + } else { + initBLS12(z); + } + } + bool calcG1(G1& P, const Fp& t) const + { + if (isBN_) { + if (!calcBN<G1, Fp>(P, t)) return false; + // no subgroup + } else { +#ifdef MCL_USE_OLD_MAPTO_FOR_BLS12 + naiveMapTo<G1, Fp>(P, t); +#else + if (!calcBN<G1, Fp>(P, t)) return false; +#endif + mulByCofactorBLS12(P, P); + } + assert(P.isValid()); + return true; + } + /* + get the element in G2 by multiplying the cofactor + */ + bool calcG2(G2& P, const Fp2& t) const + { + if (isBN_) { + if (!calcBN<G2, Fp2>(P, t)) return false; + mulByCofactorBN(P, P); + } else { +#ifdef MCL_USE_OLD_MAPTO_FOR_BLS12 + naiveMapTo<G1, Fp>(P, t); +#else + if (!calcBN<G2, Fp2>(P, t)) return false; +#endif + mulByCofactorBLS12(P, P); + } + 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; + + 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); + } + Fp::init(pb, p, mode); + if (!*pb) return; + Fr::init(pb, r, mode); + if (!*pb) return; + Fp2::init(cp.xi_a); + 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, false); + } else { + mapTo.init(2 * p - r, z, true, cp.curveType); + } + glv1.init(r, z, isBLS12, cp.curveType); + glv2.init(r, z, isBLS12); + *pb = true; + } +#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) +{ + y.clear(); + 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; + } 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; + } +} +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 + +} } // mcl::bn + diff --git a/vendor/github.com/dexon-foundation/mcl/include/mcl/bn256.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/bn256.hpp new file mode 100644 index 000000000..7a5da7a05 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/bn384.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/bn384.hpp new file mode 100644 index 000000000..8aa14fe5c --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/bn512.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/bn512.hpp new file mode 100644 index 000000000..c87ad9035 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/conversion.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/conversion.hpp new file mode 100644 index 000000000..7a04b7fa2 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/curve_type.h b/vendor/github.com/dexon-foundation/mcl/include/mcl/curve_type.h new file mode 100644 index 000000000..5957d1ae8 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/curve_type.h @@ -0,0 +1,18 @@ +#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 +}; diff --git a/vendor/github.com/dexon-foundation/mcl/include/mcl/ec.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/ec.hpp new file mode 100644 index 000000000..8ebf7e757 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/ec.hpp @@ -0,0 +1,1019 @@ +#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, + Proj +}; + +} // mcl::ecl + +/* + 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) + { + const bool isQzOne = Q.z.isOne(); + Fp r, U1, S1, H, H3; + Fp::sqr(r, P.z); + if (isQzOne) { + U1 = P.x; + Fp::mul(H, Q.x, r); + H -= U1; + r *= P.z; + S1 = P.y; + } else { + Fp::sqr(S1, Q.z); + Fp::mul(U1, P.x, S1); + Fp::mul(H, Q.x, r); + H -= U1; + r *= P.z; + S1 *= Q.z; + S1 *= P.y; + } + r *= Q.y; + r -= S1; + if (H.isZero()) { + if (r.isZero()) { + dblNoVerifyInf(R, P); + } else { + R.clear(); + } + return; + } + if (isQzOne) { + Fp::mul(R.z, P.z, H); + } else { + Fp::mul(R.z, P.z, Q.z); + R.z *= H; + } + 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) + { + const bool isQzOne = Q.z.isOne(); + 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); + } + 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 { + Fp::mul(R.z, P.z, Q.z); + } + 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& P0, const EcT& Q0) + { + if (P0.isZero()) { R = Q0; return; } + if (Q0.isZero()) { R = P0; return; } + if (&P0 == &Q0) { + dblNoVerifyInf(R, P0); + return; + } +#ifdef MCL_EC_USE_AFFINE + const EcT& P(P0); + const EcT& Q(Q0); + 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 + const EcT *pP = &P0; + const EcT *pQ = &Q0; + if (pP->z.isOne()) { + fp::swap_(pP, pQ); + } + const EcT& P(*pP); + const EcT& Q(*pQ); + switch (mode_) { + case ec::Jacobi: + addJacobi(R, P, Q); + break; + case ec::Proj: + addProj(R, P, Q); + 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 (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 +}; + +} // 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/dexon-foundation/mcl/include/mcl/ecdsa.h b/vendor/github.com/dexon-foundation/mcl/include/mcl/ecdsa.h new file mode 100644 index 000000000..daeb6be53 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/ecdsa.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/ecdsa.hpp new file mode 100644 index 000000000..cf3ed3f65 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/ecparam.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/ecparam.hpp new file mode 100644 index 000000000..19b76bf55 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/ecparam.hpp @@ -0,0 +1,164 @@ +#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> + +namespace mcl { namespace ecparam { + +const struct mcl::EcParam secp160k1 = { + "secp160k1", + "0xfffffffffffffffffffffffffffffffeffffac73", + "0", + "7", + "0x3b4c382ce37aa192a4019e763036f4f5dd4d7ebb", + "0x938cf935318fdced6bc28286531733c3f03c4fee", + "0x100000000000000000001b8fa16dfab9aca16b6b3", + 160 +}; +// p=2^160 + 7 +const struct mcl::EcParam p160_1 = { + "p160_1", + "0x10000000000000000000000000000000000000007", + "10", + "1343632762150092499701637438970764818528075565078", + "1", + "1236612389951462151661156731535316138439983579284", + "1461501637330902918203683518218126812711137002561", + 161 +}; +const struct mcl::EcParam secp192k1 = { + "secp192k1", + "0xfffffffffffffffffffffffffffffffffffffffeffffee37", + "0", + "3", + "0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7d", + "0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9d", + "0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d", + 192 +}; +const struct mcl::EcParam secp224k1 = { + "secp224k1", + "0xfffffffffffffffffffffffffffffffffffffffffffffffeffffe56d", + "0", + "5", + "0xa1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45c", + "0x7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5", + "0x10000000000000000000000000001dce8d2ec6184caf0a971769fb1f7", + 224 +}; +const struct mcl::EcParam secp256k1 = { + "secp256k1", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "0", + "7", + "0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + 256 +}; +const struct mcl::EcParam secp384r1 = { + "secp384r1", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff", + "-3", + "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", + "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973", + 384 +}; +const struct mcl::EcParam secp521r1 = { + "secp521r1", + "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "-3", + "0x51953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", + "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", + 521 +}; +const struct mcl::EcParam NIST_P192 = { + "NIST_P192", + "0xfffffffffffffffffffffffffffffffeffffffffffffffff", + "-3", + "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", + "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", + "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811", + "0xffffffffffffffffffffffff99def836146bc9b1b4d22831", + 192 +}; +const struct mcl::EcParam NIST_P224 = { + "NIST_P224", + "0xffffffffffffffffffffffffffffffff000000000000000000000001", + "-3", + "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", + "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", + "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", + "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d", + 224 +}; +const struct mcl::EcParam NIST_P256 = { + "NIST_P256", + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "-3", + "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", + "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + 256 +}; +// same secp384r1 +const struct mcl::EcParam NIST_P384 = { + "NIST_P384", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff", + "-3", + "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", + "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973", + 384 +}; +// same secp521r1 +const struct mcl::EcParam NIST_P521 = { + "NIST_P521", + "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "-3", + "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", + "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", + 521 +}; + +} // 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 + +} // mcl diff --git a/vendor/github.com/dexon-foundation/mcl/include/mcl/elgamal.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/elgamal.hpp new file mode 100644 index 000000000..8bc3104b7 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/elgamal.hpp @@ -0,0 +1,620 @@ +#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 + */ + template<class Hash> + void encWithZkp(CipherText& c, Zkp& zkp, int m, Hash& hash, 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; + hash.update(os.str()); + const std::string digest = hash.digest(); + Zn cc; + cc.setArrayMask(digest.c_str(), digest.size()); + 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; + hash.update(os.str()); + const std::string digest = hash.digest(); + Zn cc; + cc.setArrayMask(digest.c_str(), digest.size()); + zkp.c0 = cc - zkp.c1; + zkp.s0 = r0 + zkp.c0 * u; + } + } + /* + verify cipher text with ZKP + */ + template<class Hash> + bool verify(const CipherText& c, const Zkp& zkp, Hash& hash) 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; + hash.update(os.str()); + const std::string digest = hash.digest(); + Zn cc; + cc.setArrayMask(digest.c_str(), digest.size()); + 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/dexon-foundation/mcl/include/mcl/fp.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/fp.hpp new file mode 100644 index 000000000..48500127e --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/fp.hpp @@ -0,0 +1,635 @@ +#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 + +void getRandVal(Unit *out, RandGen& rg, const Unit *in, size_t bitSize); + +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"); + } + static inline void init(bool *pb, const mpz_class& _p, fp::Mode mode = fp::FP_AUTO) + { + assert(maxBitSize <= MCL_MAX_BIT_SIZE); + *pb = op_.init(_p, maxBitSize, 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 = (void (*)(FpT& z, const FpT& x, const FpT& y))op_.fp_addA_; + if (add == 0) add = addC; + sub = (void (*)(FpT& z, const FpT& x, const FpT& y))op_.fp_subA_; + if (sub == 0) sub = subC; + neg = (void (*)(FpT& y, const FpT& x))op_.fp_negA_; + if (neg == 0) neg = negC; + mul = (void (*)(FpT& z, const FpT& x, const FpT& y))op_.fp_mulA_; + if (mul == 0) mul = mulC; + sqr = (void (*)(FpT& y, const FpT& x))op_.fp_sqrA_; + if (sqr == 0) sqr = sqrC; +#endif + *pb = true; + } + 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); + } + template<class S> + void setArray(bool *pb, const S *x, size_t n) + { + *pb = fp::copyAndMask(v_, x, sizeof(S) * n, op_, fp::NoMask); + 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(fp::RandGen rg = fp::RandGen()) + { + if (rg.isZero()) rg = fp::RandGen::get(); + fp::getRandVal(v_, rg, op_.p, op_.bitSize); + toMont(); + } + 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(const mpz_class& _p, fp::Mode mode = fp::FP_AUTO) + { + bool b; + init(&b, _p, mode); + if (!b) throw cybozu::Exception("Fp:init"); + } + static inline void init(const std::string& mstr, fp::Mode mode = fp::FP_AUTO) + { + bool b; + init(&b, mstr.c_str(), mode); + if (!b) throw cybozu::Exception("Fp:init"); + } + 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:neg"); + } + 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/dexon-foundation/mcl/include/mcl/fp_tower.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/fp_tower.hpp new file mode 100644 index 000000000..63738a3f5 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/fp_tower.hpp @@ -0,0 +1,1342 @@ +#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 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); } +#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); } +#endif + 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_); } + 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_); } + static void (*addPre)(FpDblT& z, const FpDblT& x, const FpDblT& y); + static void (*subPre)(FpDblT& z, const FpDblT& x, const FpDblT& y); + /* + 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 = (void (*)(FpDblT&, const FpDblT&, const FpDblT&))op.fpDbl_addA_; + if (add == 0) add = addC; + sub = (void (*)(FpDblT&, const FpDblT&, const FpDblT&))op.fpDbl_subA_; + if (sub == 0) sub = subC; + mod = (void (*)(Fp&, const FpDblT&))op.fpDbl_modA_; + if (mod == 0) mod = modC; +#endif + if (op.fpDbl_addPreA_) { + addPre = (void (*)(FpDblT&, const FpDblT&, const FpDblT&))op.fpDbl_addPreA_; + } else { + addPre = addPreC; + } + if (op.fpDbl_subPreA_) { + subPre = (void (*)(FpDblT&, const FpDblT&, const FpDblT&))op.fpDbl_subPreA_; + } else { + subPre = subPreC; + } + if (op.fpDbl_mulPreA_) { + mulPre = (void (*)(FpDblT&, const Fp&, const Fp&))op.fpDbl_mulPreA_; + } else { + mulPre = mulPreC; + } + if (op.fpDbl_sqrPreA_) { + sqrPre = (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&); +#endif +template<class Fp> void (*FpDblT<Fp>::addPre)(FpDblT&, const FpDblT&, const FpDblT&); +template<class Fp> void (*FpDblT<Fp>::subPre)(FpDblT&, const FpDblT&, const FpDblT&); +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 uint32_t xi_a_; + 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_; + } + 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); + 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 xi_a_; } + static void init(uint32_t xi_a) + { +// assert(Fp::maxSize <= 256); + xi_a_ = xi_a; + mcl::fp::Op& op = Fp::op_; + add = (void (*)(Fp2T& z, const Fp2T& x, const Fp2T& y))op.fp2_addA_; + if (add == 0) add = fp2_addC; + sub = (void (*)(Fp2T& z, const Fp2T& x, const Fp2T& y))op.fp2_subA_; + if (sub == 0) sub = fp2_subC; + neg = (void (*)(Fp2T& y, const Fp2T& x))op.fp2_negA_; + if (neg == 0) neg = fp2_negC; + mul = (void (*)(Fp2T& z, const Fp2T& x, const Fp2T& y))op.fp2_mulA_; + if (mul == 0) { + if (op.isFastMod) { + mul = fp2_mulC; + } else if (!op.isFullBit) { + if (0 && sizeof(Fp) * 8 == op.N * fp::UnitBitSize && op.fp2_mulNF) { + mul = fp2_mulNFW; + } else { + mul = fp2_mulC; + } + } else { + mul = fp2_mulC; + } + } + sqr = (void (*)(Fp2T& y, const Fp2T& x))op.fp2_sqrA_; + if (sqr == 0) sqr = fp2_sqrC; + op.fp2_inv = fp2_invW; + if (xi_a == 1) { + /* + current fp_generator.hpp generates mul_xi for xi_a = 1 + */ + if (op.fp2_mul_xiA_) { + mul_xi = (void (*)(Fp2T&, const Fp2T&))op.fp2_mul_xiA_; + } else { + mul_xi = fp2_mul_xi_1_1i; + } + } 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(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 fp2_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 fp2_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 fp2_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; + } +#endif + 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); + } + static void fp2_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 fp2_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, xi_a_); + t -= b; + Fp::mulUnit(y.b, b, 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_1i(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]); + } +}; + +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); +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 = (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 = (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> uint32_t Fp2T<Fp>::xi_a_; +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]; + +/* + 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 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 + } + /* + 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 mul(Fp6T& z, const Fp6T& x, const Fp6T& 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; +#if 1 + Fp2Dbl AD, BE, CF; + Fp2Dbl::mulPre(AD, a, d); + Fp2Dbl::mulPre(BE, b, e); + Fp2Dbl::mulPre(CF, 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, CF); + 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, AD); + Fp2Dbl::sub(T2, T2, BE); + + Fp2::add(t3, a, c); + Fp2::add(t4, d, f); + Fp2Dbl T3; + Fp2Dbl::mulPre(T3, t3, t4); + Fp2Dbl::sub(T3, T3, AD); + Fp2Dbl::sub(T3, T3, CF); + + Fp2Dbl::add(AD, AD, T1); + Fp2Dbl::mod(z.a, AD); + Fp2Dbl::mul_xi(CF, CF); + Fp2Dbl::add(CF, CF, T2); + Fp2Dbl::mod(z.b, CF); + Fp2Dbl::add(T3, T3, BE); + Fp2Dbl::mod(z.c, T3); +#else + Fp2 ad, be, cf; + Fp2::mul(ad, a, d); + Fp2::mul(be, b, e); + Fp2::mul(cf, c, f); + + Fp2 t1, t2, t3, t4; + Fp2::add(t1, b, c); + Fp2::add(t2, e, f); + t1 *= t2; + t1 -= be; + t1 -= cf; + Fp2::mul_xi(t1, t1); + + Fp2::add(t2, a, b); + Fp2::add(t3, e, d); + t2 *= t3; + t2 -= ad; + t2 -= be; + + Fp2::add(t3, a, c); + Fp2::add(t4, d, f); + t3 *= t4; + t3 -= ad; + t3 -= cf; + + Fp2::add(z.a, ad, t1); + Fp2::mul_xi(z.b, cf); + z.b += t2; + Fp2::add(z.c, t3, be); +#endif +//clk.end(); + } + /* + 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); + } +}; + +/* + 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 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); + } + /* + 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) + { + const Fp6& a = x.a; + const Fp6& b = x.b; + const Fp6& c = y.a; + const Fp6& d = y.b; + Fp6 t1, t2, ac, bd; + Fp6::add(t1, a, b); + Fp6::add(t2, c, d); + 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); + } + /* + 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/dexon-foundation/mcl/include/mcl/gmp_util.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/gmp_util.hpp new file mode 100644 index 000000000..2dd71eb50 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/gmp_util.hpp @@ -0,0 +1,861 @@ +#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(buf, n * sizeof(buf[0])); + 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 +}; + +} // mcl diff --git a/vendor/github.com/dexon-foundation/mcl/include/mcl/lagrange.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/lagrange.hpp new file mode 100644 index 000000000..7c0218896 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/lagrange.hpp @@ -0,0 +1,97 @@ +#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) +{ + /* + 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]) + */ + if (k < 2) { + *pb = false; + return; + } + 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 +*/ +template<class G, class T> +void evaluatePolynomial(bool *pb, G& out, const G *c, size_t cSize, const T& x) +{ + if (cSize < 2) { + *pb = false; + 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/dexon-foundation/mcl/include/mcl/op.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/op.hpp new file mode 100644 index 000000000..d108d1a55 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/op.hpp @@ -0,0 +1,381 @@ +#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 { + +/* + 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 convresion + + // 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*); + +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 +}; + +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; + 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_addPreA_; + void3u fpDbl_subPreA_; + 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_addPreA_ = 0; + fpDbl_subPreA_ = 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, Mode mode, size_t mclMaxBitSize = MCL_MAX_BIT_SIZE); + void initFp2(int xi_a); +#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/dexon-foundation/mcl/include/mcl/operator.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/operator.hpp new file mode 100644 index 000000000..e9bc506df --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/paillier.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/paillier.hpp new file mode 100644 index 000000000..03e44cb16 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/randgen.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/randgen.hpp new file mode 100644 index 000000000..4bfb30b03 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/randgen.hpp @@ -0,0 +1,126 @@ +#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(void *buf, size_t bufSize) + { + // use crypto.getRandomValues + EM_ASM({Module.cryptoGetRandomValues($0, $1)}, buf, bufSize); + } +}; +} // 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> +void readWrapper(void *self, void *buf, uint32_t bufSize) +{ + reinterpret_cast<RG*>(self)->read((uint8_t*)buf, bufSize); +} + +#if 0 // #if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11 +template<> +inline void readWrapper<std::random_device>(void *self, void *buf, uint32_t bufSize) +{ + std::random_device& rg = *reinterpret_cast<std::random_device*>(self); + uint8_t *p = reinterpret_cast<uint8_t*>(buf); + uint32_t v; + while (bufSize >= 4) { + v = rg(); + memcpy(p, &v, 4); + p += 4; + bufSize -= 4; + } + if (bufSize > 0) { + v = rg(); + memcpy(p, &v, bufSize); + } +} +#endif +} // local +/* + wrapper of cryptographically secure pseudo random number generator +*/ +class RandGen { + typedef void (*readFuncType)(void *self, void *buf, uint32_t bufSize); + 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(void *out, size_t byteSize) + { + readFunc_(self_, out, static_cast<uint32_t>(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& get() + { +#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; + } + /* + rg must be thread safe + rg.read(void *buf, size_t bufSize); + */ + static void setRandGen(const RandGen& rg) + { + get() = rg; + } +}; + +} } // mcl::fp + +#ifdef _MSC_VER + #pragma warning(pop) +#endif diff --git a/vendor/github.com/dexon-foundation/mcl/include/mcl/she.h b/vendor/github.com/dexon-foundation/mcl/include/mcl/she.h new file mode 100644 index 000000000..60b399c65 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/she.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/she.hpp new file mode 100644 index 000000000..3ce361454 --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/util.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/util.hpp new file mode 100644 index 000000000..edef971cb --- /dev/null +++ b/vendor/github.com/dexon-foundation/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/dexon-foundation/mcl/include/mcl/vint.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/vint.hpp new file mode 100644 index 000000000..32a51bb64 --- /dev/null +++ b/vendor/github.com/dexon-foundation/mcl/include/mcl/vint.hpp @@ -0,0 +1,1926 @@ +#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); + 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 + */ + 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; + } + assert(yn >= 2); + /* + bitwise left shift x and y to adjust MSB of y[yn - 1] = 1 + */ + const size_t shift = sizeof(T) * 8 - 1 - cybozu::bsr(y[yn - 1]); + 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; + buf_[unitSize - 1] = 0; + memcpy(&buf_[0], x, sizeof(S) * size); + 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(&buf_[0], n * sizeof(buf_[0])); + 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) + { + const size_t maxN = MCL_MAX_BIT_SIZE / (sizeof(MCL_SIZEOF_UNIT) * 8); + 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/dexon-foundation/mcl/include/mcl/window_method.hpp b/vendor/github.com/dexon-foundation/mcl/include/mcl/window_method.hpp new file mode 100644 index 000000000..cb4fad37e --- /dev/null +++ b/vendor/github.com/dexon-foundation/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 + |