#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