commit
14fd1d125d
@ -0,0 +1,47 @@ |
||||
|
||||
Copyright (c) 2015 MITSUNARI Shigeo |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are met: |
||||
|
||||
Redistributions of source code must retain the above copyright notice, this |
||||
list of conditions and the following disclaimer. |
||||
Redistributions in binary form must reproduce the above copyright notice, |
||||
this list of conditions and the following disclaimer in the documentation |
||||
and/or other materials provided with the distribution. |
||||
Neither the name of the copyright owner nor the names of its contributors may |
||||
be used to endorse or promote products derived from this software without |
||||
specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
||||
THE POSSIBILITY OF SUCH DAMAGE. |
||||
----------------------------------------------------------------------------- |
||||
ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満た |
||||
す場合に限り、再頒布および使用が許可されます。 |
||||
|
||||
ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項 |
||||
を含めること。 |
||||
バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作 |
||||
権表示、本条件一覧、および下記免責条項を含めること。 |
||||
書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進 |
||||
に、著作権者の名前またはコントリビューターの名前を使用してはならない。 |
||||
本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供さ |
||||
れており、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性 |
||||
に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。 |
||||
著作権者もコントリビューターも、事由のいかんを問わず、 損害発生の原因いかんを |
||||
問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為で |
||||
あるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、 |
||||
本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の |
||||
喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接 |
||||
損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、 |
||||
一切責任を負わないものとします。 |
@ -0,0 +1,20 @@ |
||||
include common.mk |
||||
|
||||
all: |
||||
$(MKDIR) bin
|
||||
$(MAKE) -C test
|
||||
$(MAKE) -C sample
|
||||
|
||||
test: |
||||
$(MAKE) -C test test
|
||||
|
||||
sample: |
||||
$(MAKE) -C sample test
|
||||
|
||||
clean: |
||||
# $(MAKE) -C src clean
|
||||
$(MAKE) -C test clean
|
||||
$(MAKE) -C sample clean
|
||||
|
||||
.PHONY: sample |
||||
|
@ -0,0 +1,105 @@ |
||||
GCC_VER=$(shell $(PRE)$(CC) -dumpversion)
|
||||
UNAME_S=$(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux) |
||||
OS=Linux
|
||||
endif |
||||
ifneq ($(UNAME_S),Darwin) |
||||
LDFLAGS += -lrt
|
||||
endif |
||||
CP = cp -f
|
||||
AR = ar r
|
||||
MKDIR=mkdir -p
|
||||
RM=rm -fr
|
||||
CFLAGS_OPT+=-fomit-frame-pointer -DNDEBUG
|
||||
ifeq ($(CXX),clang++) |
||||
CFLAGS_OPT+=-O3
|
||||
else |
||||
ifeq ($(shell expr $(GCC_VER) \> 4.6.0),1)
|
||||
CFLAGS_OPT+=-Ofast
|
||||
else
|
||||
CFLAGS_OPT+=-O3
|
||||
endif
|
||||
endif |
||||
CFLAGS_WARN=-Wall -Wextra -Wformat=2 -Wcast-qual -Wcast-align -Wwrite-strings -Wfloat-equal -Wpointer-arith
|
||||
CFLAGS+= -g -D_FILE_OFFSET_BITS=64
|
||||
CFLAGS+=$(CFLAGS_WARN)
|
||||
BIT?=64
|
||||
ifeq ($(BIT),32) |
||||
CPU?=x86
|
||||
else |
||||
ifeq ($(BIT),64)
|
||||
CPU?=x64
|
||||
endif
|
||||
endif |
||||
ifeq ($(BIT),0) |
||||
BIT_OPT=
|
||||
else |
||||
BIT_OPT=-m$(BIT)
|
||||
endif |
||||
ifeq ($(MARCH),) |
||||
ifeq ($(shell expr $(GCC_VER) \> 4.2.1),1) |
||||
CFLAGS+=-march=native
|
||||
endif |
||||
else |
||||
CFLAGS+=$(MARCH)
|
||||
endif |
||||
|
||||
DEBUG=1
|
||||
ifeq ($(RELEASE),1) |
||||
DEBUG=0
|
||||
endif |
||||
|
||||
ifeq ($(DEBUG),0) |
||||
CFLAGS+=$(CFLAGS_OPT)
|
||||
OBJDIR=release
|
||||
OBJSUF=
|
||||
else |
||||
ifeq ($(OS),Linux)
|
||||
LDFLAGS+=-rdynamic
|
||||
endif
|
||||
OBJDIR=debug
|
||||
OBJSUF=d
|
||||
endif |
||||
|
||||
####################################################
|
||||
|
||||
LDFLAGS += -lpthread -m$(BIT) -lgmp -lgmpxx
|
||||
|
||||
####################################################
|
||||
|
||||
TOPDIR:=$(realpath $(dir $(lastword $(MAKEFILE_LIST))))/
|
||||
EXTDIR:=$(TOPDIR)../cybozulib_ext/
|
||||
CFLAGS+= -I$(TOPDIR)include -I$(TOPDIR)../cybozulib/include/ -I$(TOPDIR)../xbyak/ $(BIT_OPT) $(INC_DIR)
|
||||
LDFLAGS+= -L$(TOPDIR)lib $(BIT_OPT) -Wl,-rpath,'$$ORIGIN/../lib' $(LD_DIR)
|
||||
|
||||
MKDEP = sh -ec '$(PRE)$(CC) -MM $(CFLAGS) $< | sed "s@\($*\)\.o[ :]*@$(OBJDIR)/\1.o $@ : @g" > $@; [ -s $@ ] || rm -f $@; touch $@'
|
||||
|
||||
CLEAN=$(RM) $(TARGET) $(OBJDIR)
|
||||
|
||||
define UNIT_TEST |
||||
sh -ec 'for i in $(TARGET); do $$i|grep "ctest:name"; done' > result.txt |
||||
grep -v "ng=0, exception=0" result.txt || echo "all unit tests are ok" |
||||
endef |
||||
|
||||
define SAMPLE_TEST |
||||
sh -ec 'for i in $(TARGET); do $$i; done' |
||||
endef |
||||
|
||||
.SUFFIXES: .cpp .d .exe |
||||
|
||||
$(OBJDIR)/%.o: %.cpp |
||||
$(PRE)$(CXX) -c $< -o $@ $(CFLAGS)
|
||||
|
||||
$(OBJDIR)/%.d: %.cpp $(OBJDIR) |
||||
@$(MKDEP)
|
||||
|
||||
$(TOPDIR)bin/%$(OBJSUF).exe: $(OBJDIR)/%.o $(LIBS) |
||||
$(PRE)$(CXX) $< -o $@ $(LIBS) $(LDFLAGS)
|
||||
|
||||
OBJS=$(addprefix $(OBJDIR)/,$(SRC:.cpp=.o))
|
||||
|
||||
DEPEND_FILE=$(addprefix $(OBJDIR)/, $(SRC:.cpp=.d))
|
||||
TEST_FILE=$(addprefix $(TOPDIR)bin/, $(SRC:.cpp=$(OBJSUF).exe))
|
||||
|
||||
.PHONY: test |
||||
|
@ -0,0 +1,26 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ImportGroup Label="PropertySheets" /> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup> |
||||
<OutDir>$(SolutionDir)bin\</OutDir> |
||||
</PropertyGroup> |
||||
<ItemDefinitionGroup> |
||||
<ClCompile> |
||||
<AdditionalIncludeDirectories>$(SolutionDir)../cybozulib/include;$(SolutionDir)../cybozulib_ext/mpir/include;$(SolutionDir)include</AdditionalIncludeDirectories> |
||||
</ClCompile> |
||||
</ItemDefinitionGroup> |
||||
<ItemDefinitionGroup> |
||||
<ClCompile> |
||||
<WarningLevel>Level4</WarningLevel> |
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> |
||||
<PrecompiledHeaderFile /> |
||||
<PrecompiledHeaderOutputFile /> |
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);NOMINMAX</PreprocessorDefinitions> |
||||
</ClCompile> |
||||
<Link> |
||||
<AdditionalLibraryDirectories>$(SolutionDir)../cybozulib_ext/mpir/lib</AdditionalLibraryDirectories> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup /> |
||||
</Project> |
@ -0,0 +1,14 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ImportGroup Label="PropertySheets" /> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup> |
||||
<TargetName>$(ProjectName)d</TargetName> |
||||
</PropertyGroup> |
||||
<ItemDefinitionGroup> |
||||
<ClCompile> |
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> |
||||
</ClCompile> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup /> |
||||
</Project> |
@ -0,0 +1,585 @@ |
||||
#pragma once |
||||
/**
|
||||
@file |
||||
@brief elliptic curve |
||||
@author MITSUNARI Shigeo(@herumi) |
||||
@license modified new BSD license |
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
*/ |
||||
#include <sstream> |
||||
#include <cybozu/exception.hpp> |
||||
#include <cybozu/bitvector.hpp> |
||||
#include <mcl/operator.hpp> |
||||
#include <mcl/power.hpp> |
||||
#include <mcl/gmp_util.hpp> |
||||
|
||||
namespace mcl { |
||||
|
||||
#define MCL_EC_USE_AFFINE 0 |
||||
#define MCL_EC_USE_PROJ 1 |
||||
#define MCL_EC_USE_JACOBI 2 |
||||
|
||||
//#define MCL_EC_COORD MCL_EC_USE_JACOBI
|
||||
//#define MCL_EC_COORD MCL_EC_USE_PROJ
|
||||
#ifndef MCL_EC_COORD |
||||
#define MCL_EC_COORD MCL_EC_USE_PROJ |
||||
#endif |
||||
/*
|
||||
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 ope::addsub<EcT<_Fp>, |
||||
ope::comparable<EcT<_Fp>, |
||||
ope::hasNegative<EcT<_Fp> > > > { |
||||
enum { |
||||
zero, |
||||
minus3, |
||||
generic |
||||
}; |
||||
public: |
||||
typedef _Fp Fp; |
||||
typedef typename Fp::BlockType BlockType; |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
Fp x, y; |
||||
bool inf_; |
||||
#else |
||||
mutable Fp x, y, z; |
||||
#endif |
||||
static Fp a_; |
||||
static Fp b_; |
||||
static int specialA_; |
||||
static bool compressedExpression_; |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
EcT() : inf_(true) {} |
||||
#else |
||||
EcT() { z.clear(); } |
||||
#endif |
||||
EcT(const Fp& _x, const Fp& _y) |
||||
{ |
||||
set(_x, _y); |
||||
} |
||||
void normalize() const |
||||
{ |
||||
#if MCL_EC_COORD == MCL_EC_USE_JACOBI |
||||
if (isZero() || z == 1) return; |
||||
Fp rz, rz2; |
||||
Fp::inv(rz, z); |
||||
rz2 = rz * rz; |
||||
x *= rz2; |
||||
y *= rz2 * rz; |
||||
z = 1; |
||||
#elif MCL_EC_COORD == MCL_EC_USE_PROJ |
||||
if (isZero() || z == 1) return; |
||||
Fp rz; |
||||
Fp::inv(rz, z); |
||||
x *= rz; |
||||
y *= rz; |
||||
z = 1; |
||||
#endif |
||||
} |
||||
|
||||
static inline void setParam(const std::string& astr, const std::string& bstr) |
||||
{ |
||||
a_.fromStr(astr); |
||||
b_.fromStr(bstr); |
||||
if (a_.isZero()) { |
||||
specialA_ = zero; |
||||
} else if (a_ == -3) { |
||||
specialA_ = minus3; |
||||
} else { |
||||
specialA_ = generic; |
||||
} |
||||
} |
||||
static inline bool isValid(const Fp& _x, const Fp& _y) |
||||
{ |
||||
return _y * _y == (_x * _x + a_) * _x + b_; |
||||
} |
||||
void set(const Fp& _x, const Fp& _y, bool verify = true) |
||||
{ |
||||
if (verify && !isValid(_x, _y)) throw cybozu::Exception("ec:EcT:set") << _x << _y; |
||||
x = _x; y = _y; |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
inf_ = false; |
||||
#else |
||||
z = 1; |
||||
#endif |
||||
} |
||||
void clear() |
||||
{ |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
inf_ = true; |
||||
#else |
||||
z = 0; |
||||
#endif |
||||
x.clear(); |
||||
y.clear(); |
||||
} |
||||
|
||||
static inline void dbl(EcT& R, const EcT& P, bool verifyInf = true) |
||||
{ |
||||
if (verifyInf) { |
||||
if (P.isZero()) { |
||||
R.clear(); return; |
||||
} |
||||
} |
||||
#if MCL_EC_COORD == MCL_EC_USE_JACOBI |
||||
Fp S, M, t, y2; |
||||
Fp::square(y2, P.y); |
||||
Fp::mul(S, P.x, y2); |
||||
S += S; |
||||
S += S; |
||||
Fp::square(M, P.x); |
||||
switch (specialA_) { |
||||
case zero: |
||||
Fp::add(t, M, M); |
||||
M += t; |
||||
break; |
||||
case minus3: |
||||
Fp::square(t, P.z); |
||||
Fp::square(t, t); |
||||
M -= t; |
||||
Fp::add(t, M, M); |
||||
M += t; |
||||
break; |
||||
case generic: |
||||
default: |
||||
Fp::square(t, P.z); |
||||
Fp::square(t, t); |
||||
t *= a_; |
||||
t += M; |
||||
M += M; |
||||
M += t; |
||||
break; |
||||
} |
||||
Fp::square(R.x, M); |
||||
R.x -= S; |
||||
R.x -= S; |
||||
Fp::mul(R.z, P.y, P.z); |
||||
R.z += R.z; |
||||
Fp::square(y2, y2); |
||||
y2 += y2; |
||||
y2 += y2; |
||||
y2 += y2; |
||||
Fp::sub(R.y, S, R.x); |
||||
R.y *= M; |
||||
R.y -= y2; |
||||
#elif MCL_EC_COORD == MCL_EC_USE_PROJ |
||||
Fp w, t, h; |
||||
switch (specialA_) { |
||||
case zero: |
||||
Fp::square(w, P.x); |
||||
Fp::add(t, w, w); |
||||
w += t; |
||||
break; |
||||
case minus3: |
||||
Fp::square(w, P.x); |
||||
Fp::square(t, P.z); |
||||
w -= t; |
||||
Fp::add(t, w, w); |
||||
w += t; |
||||
break; |
||||
case generic: |
||||
default: |
||||
Fp::square(w, P.z); |
||||
w *= a_; |
||||
Fp::square(t, P.x); |
||||
w += t; |
||||
w += t; |
||||
w += t; // w = a z^2 + 3x^2
|
||||
break; |
||||
} |
||||
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::square(h, w); |
||||
h -= t; |
||||
h -= t; // w^2 - 8B
|
||||
Fp::mul(R.x, h, R.z); |
||||
t -= h; // h is free
|
||||
t *= w; |
||||
Fp::square(w, P.y); |
||||
R.x += R.x; |
||||
R.z += R.z; |
||||
Fp::square(h, R.z); |
||||
w *= h; |
||||
R.z *= h; |
||||
Fp::sub(R.y, t, w); |
||||
R.y -= w; |
||||
#else |
||||
Fp t, s; |
||||
Fp::square(t, P.x); |
||||
Fp::add(s, t, t); |
||||
t += s; |
||||
t += a_; |
||||
Fp::add(s, P.y, P.y); |
||||
t /= s; |
||||
Fp::square(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; |
||||
#endif |
||||
} |
||||
static inline void add(EcT& R, const EcT& P, const EcT& Q) |
||||
{ |
||||
if (P.isZero()) { R = Q; return; } |
||||
if (Q.isZero()) { R = P; return; } |
||||
#if MCL_EC_COORD == MCL_EC_USE_JACOBI |
||||
Fp r, U1, S1, H, H3; |
||||
Fp::square(r, P.z); |
||||
Fp::square(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; |
||||
Fp::mul(r, Q.y, r); |
||||
r -= S1; |
||||
if (H.isZero()) { |
||||
if (r.isZero()) { |
||||
dbl(R, P, false); |
||||
} else { |
||||
R.clear(); |
||||
} |
||||
return; |
||||
} |
||||
Fp::mul(R.z, P.z, Q.z); |
||||
R.z *= H; |
||||
Fp::square(H3, H); // H^2
|
||||
Fp::square(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); |
||||
#elif MCL_EC_COORD == MCL_EC_USE_PROJ |
||||
Fp r, PyQz, v, A, vv; |
||||
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()) { |
||||
Fp::add(vv, A, PyQz); |
||||
if (vv.isZero()) { |
||||
R.clear(); |
||||
} else { |
||||
dbl(R, P, false); |
||||
} |
||||
return; |
||||
} |
||||
Fp::sub(R.y, A, PyQz); |
||||
Fp::square(A, R.y); |
||||
Fp::square(vv, v); |
||||
r *= vv; |
||||
vv *= v; |
||||
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; |
||||
#else |
||||
Fp t; |
||||
Fp::neg(t, Q.y); |
||||
if (P.y == t) { R.clear(); return; } |
||||
Fp::sub(t, Q.x, P.x); |
||||
if (t.isZero()) { |
||||
dbl(R, P, false); |
||||
return; |
||||
} |
||||
Fp s; |
||||
Fp::sub(s, Q.y, P.y); |
||||
Fp::div(t, s, t); |
||||
R.inf_ = false; |
||||
Fp x3; |
||||
Fp::square(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; |
||||
#endif |
||||
} |
||||
static inline void sub(EcT& R, const EcT& P, const EcT& Q) |
||||
{ |
||||
#if 0 |
||||
if (P.inf_) { neg(R, Q); return; } |
||||
if (Q.inf_) { R = P; return; } |
||||
if (P.y == Q.y) { R.clear(); return; } |
||||
Fp t; |
||||
Fp::sub(t, Q.x, P.x); |
||||
if (t.isZero()) { |
||||
dbl(R, P, false); |
||||
return; |
||||
} |
||||
Fp s; |
||||
Fp::add(s, Q.y, P.y); |
||||
Fp::neg(s, s); |
||||
Fp::div(t, s, t); |
||||
R.inf_ = false; |
||||
Fp x3; |
||||
Fp::mul(x3, t, 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 |
||||
EcT nQ; |
||||
neg(nQ, Q); |
||||
add(R, P, nQ); |
||||
#endif |
||||
} |
||||
static inline void neg(EcT& R, const EcT& P) |
||||
{ |
||||
if (P.isZero()) { |
||||
R.clear(); |
||||
return; |
||||
} |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
R.inf_ = false; |
||||
R.x = P.x; |
||||
Fp::neg(R.y, P.y); |
||||
#else |
||||
R.x = P.x; |
||||
Fp::neg(R.y, P.y); |
||||
R.z = P.z; |
||||
#endif |
||||
} |
||||
template<class N> |
||||
static inline void power(EcT& z, const EcT& x, const N& y) |
||||
{ |
||||
power_impl::power(z, x, y); |
||||
} |
||||
/*
|
||||
0 <= P for any P |
||||
(Px, Py) <= (P'x, P'y) iff Px < P'x or Px == P'x and Py <= P'y |
||||
*/ |
||||
static inline int compare(const EcT& P, const EcT& Q) |
||||
{ |
||||
P.normalize(); |
||||
Q.normalize(); |
||||
if (P.isZero()) { |
||||
if (Q.isZero()) return 0; |
||||
return -1; |
||||
} |
||||
if (Q.isZero()) return 1; |
||||
int c = _Fp::compare(P.x, Q.x); |
||||
if (c > 0) return 1; |
||||
if (c < 0) return -1; |
||||
return _Fp::compare(P.y, Q.y); |
||||
} |
||||
bool isZero() const |
||||
{ |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
return inf_; |
||||
#else |
||||
return z.isZero(); |
||||
#endif |
||||
} |
||||
friend inline std::ostream& operator<<(std::ostream& os, const EcT& self) |
||||
{ |
||||
if (self.isZero()) { |
||||
return os << '0'; |
||||
} else { |
||||
self.normalize(); |
||||
os << self.x.toStr(16) << '_'; |
||||
if (compressedExpression_) { |
||||
return os << Fp::isYodd(self.y); |
||||
} else { |
||||
return os << self.y.toStr(16); |
||||
} |
||||
} |
||||
} |
||||
friend inline std::istream& operator>>(std::istream& is, EcT& self) |
||||
{ |
||||
std::string str; |
||||
is >> str; |
||||
if (str == "0") { |
||||
self.clear(); |
||||
} else { |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
self.inf_ = false; |
||||
#else |
||||
self.z = 1; |
||||
#endif |
||||
size_t pos = str.find('_'); |
||||
if (pos == std::string::npos) throw cybozu::Exception("EcT:operator>>:bad format") << str; |
||||
str[pos] = '\0'; |
||||
self.x.fromStr(&str[0], 16); |
||||
if (compressedExpression_) { |
||||
const char c = str[pos + 1]; |
||||
if ((c == '0' || c == '1') && str.size() == pos + 2) { |
||||
getYfromX(self.y, self.x, c == '1'); |
||||
} else { |
||||
str[pos] = '_'; |
||||
throw cybozu::Exception("EcT:operator>>:bad y") << str; |
||||
} |
||||
} else { |
||||
self.y.fromStr(&str[pos + 1], 16); |
||||
} |
||||
} |
||||
return is; |
||||
} |
||||
static inline void setCompressedExpression(bool compressedExpression) |
||||
{ |
||||
compressedExpression_ = compressedExpression; |
||||
} |
||||
/*
|
||||
append to bv(not clear bv) |
||||
*/ |
||||
void appendToBitVec(cybozu::BitVector& bv) const |
||||
{ |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
#error "not implemented" |
||||
#else |
||||
normalize(); |
||||
const size_t bitLen = _Fp::getModBitLen(); |
||||
/*
|
||||
elem |x|y|z| |
||||
size n n 1 if not compressed |
||||
size n 1 1 if compressed |
||||
*/ |
||||
const size_t maxBitLen = compressedExpression_ ? (bitLen + 1 + 1) : (bitLen * 2 + 1); |
||||
if (isZero()) { |
||||
bv.resize(bv.size() + maxBitLen); |
||||
return; |
||||
} |
||||
x.appendToBitVec(bv); |
||||
if (compressedExpression_) { |
||||
bv.append(Fp::isYodd(y), 1); |
||||
} else { |
||||
y.appendToBitVec(bv); |
||||
} |
||||
bv.append(1, 1); // z = 1
|
||||
#endif |
||||
} |
||||
void fromBitVec(const cybozu::BitVector& bv) |
||||
{ |
||||
#if MCL_EC_COORD == MCL_EC_USE_AFFINE |
||||
#error "not implemented" |
||||
#else |
||||
const size_t bitLen = _Fp::getModBitLen(); |
||||
const size_t maxBitLen = compressedExpression_ ? (bitLen + 1 + 1) : (bitLen * 2 + 1); |
||||
if (bv.size() != maxBitLen) { |
||||
throw cybozu::Exception("EcT:fromBitVec:bad size") << bv.size() << maxBitLen; |
||||
} |
||||
if (!bv.get(maxBitLen - 1)) { // if z = 0
|
||||
clear(); |
||||
return; |
||||
} |
||||
cybozu::BitVector t; |
||||
bv.extract(t, 0, bitLen); |
||||
x.fromBitVec(t); |
||||
if (compressedExpression_) { |
||||
bool odd = bv.get(bitLen); // y
|
||||
getYfromX(y, x, odd); |
||||
} else { |
||||
bv.extract(t, bitLen, bitLen); |
||||
y.fromBitVec(t); |
||||
} |
||||
z = 1; |
||||
#endif |
||||
} |
||||
static inline size_t getBitVecSize() |
||||
{ |
||||
const size_t bitLen = _Fp::getModBitLen(); |
||||
if (compressedExpression_) { |
||||
return bitLen + 2; |
||||
} else { |
||||
return bitLen * 2 + 1;; |
||||
} |
||||
} |
||||
static inline void getYfromX(Fp& y, const Fp& x, bool isYodd) |
||||
{ |
||||
Fp t; |
||||
Fp::square(t, x); |
||||
t += a_; |
||||
t *= x; |
||||
t += b_; |
||||
Fp::squareRoot(y, t); |
||||
if (Fp::isYodd(y) ^ isYodd) { |
||||
Fp::neg(y, y); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
template<class T> |
||||
struct TagMultiGr<EcT<T> > { |
||||
static void square(EcT<T>& z, const EcT<T>& x) |
||||
{ |
||||
EcT<T>::dbl(z, x); |
||||
} |
||||
static void mul(EcT<T>& z, const EcT<T>& x, const EcT<T>& y) |
||||
{ |
||||
EcT<T>::add(z, x, y); |
||||
} |
||||
static void inv(EcT<T>& z, const EcT<T>& x) |
||||
{ |
||||
EcT<T>::neg(z, x); |
||||
} |
||||
static void div(EcT<T>& z, const EcT<T>& x, const EcT<T>& y) |
||||
{ |
||||
EcT<T>::sub(z, x, y); |
||||
} |
||||
static void init(EcT<T>& x) |
||||
{ |
||||
x.clear(); |
||||
} |
||||
}; |
||||
|
||||
template<class _Fp> _Fp EcT<_Fp>::a_; |
||||
template<class _Fp> _Fp EcT<_Fp>::b_; |
||||
template<class _Fp> int EcT<_Fp>::specialA_; |
||||
template<class _Fp> bool EcT<_Fp>::compressedExpression_; |
||||
|
||||
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 bitLen; // bit length of p
|
||||
}; |
||||
|
||||
} // mcl
|
||||
|
||||
namespace std { CYBOZU_NAMESPACE_TR1_BEGIN |
||||
template<class T> struct hash; |
||||
|
||||
template<class _Fp> |
||||
struct hash<mcl::EcT<_Fp> > { |
||||
size_t operator()(const mcl::EcT<_Fp>& P) const |
||||
{ |
||||
if (P.isZero()) return 0; |
||||
P.normalize(); |
||||
uint64_t v = hash<_Fp>()(P.x); |
||||
v = hash<_Fp>()(P.y, v); |
||||
return static_cast<size_t>(v); |
||||
} |
||||
}; |
||||
|
||||
CYBOZU_NAMESPACE_TR1_END } // std
|
@ -0,0 +1,161 @@ |
||||
#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
|
||||
|
||||
static inline const mcl::EcParam* getEcParam(const std::string& name) |
||||
{ |
||||
static const mcl::EcParam *tbl[] = { |
||||
&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; |
||||
} |
||||
|
||||
} // mcl
|
@ -0,0 +1,446 @@ |
||||
#pragma once |
||||
/**
|
||||
@file |
||||
@brief finite field class
|
||||
@author MITSUNARI Shigeo(@herumi) |
||||
@license modified new BSD license |
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
*/ |
||||
#include <sstream> |
||||
#include <vector> |
||||
#ifdef _MSC_VER |
||||
#pragma warning(push) |
||||
#pragma warning(disable : 4127) |
||||
#ifndef NOMINMAX |
||||
#define NOMINMAX |
||||
#endif |
||||
#endif |
||||
#if defined(_WIN64) || defined(__x86_64__) |
||||
// #define USE_MONT_FP
|
||||
#endif |
||||
#include <cybozu/hash.hpp> |
||||
#include <cybozu/itoa.hpp> |
||||
#include <cybozu/atoi.hpp> |
||||
#include <cybozu/bitvector.hpp> |
||||
#include <mcl/fp_base.hpp> |
||||
#include <mcl/fp_util.hpp> |
||||
#include <mcl/gmp_util.hpp> |
||||
#include <mcl/power.hpp> |
||||
|
||||
#ifndef MCL_FP_BLOCK_MAX_BIT_N |
||||
#define MCL_FP_BLOCK_MAX_BIT_N 521 |
||||
#endif |
||||
|
||||
namespace mcl { |
||||
|
||||
struct Block { |
||||
typedef fp::Unit Unit; |
||||
const Unit *p; // pointer to original FpT.v_
|
||||
size_t n; |
||||
static const size_t UnitByteN = sizeof(Unit); |
||||
static const size_t maxUnitN = (MCL_FP_BLOCK_MAX_BIT_N + UnitByteN * 8 - 1) / (UnitByteN * 8); |
||||
Unit v_[maxUnitN]; |
||||
}; |
||||
|
||||
template<class tag = fp::TagDefault, size_t maxBitN = MCL_FP_BLOCK_MAX_BIT_N> |
||||
class FpT { |
||||
typedef fp::Unit Unit; |
||||
static const size_t UnitByteN = sizeof(Unit); |
||||
static const size_t maxUnitN = (maxBitN + UnitByteN * 8 - 1) / (UnitByteN * 8); |
||||
static fp::Op op_; |
||||
static mcl::SquareRoot sq_; |
||||
static size_t pBitLen_; |
||||
template<class tag2, size_t maxBitN2> friend class FpT; |
||||
Unit v_[maxUnitN]; |
||||
public: |
||||
// return pointer to array v_[]
|
||||
const Unit *getUnit() const { return v_; } |
||||
size_t getUnitN() const { return op_.N; } |
||||
typedef Unit BlockType; |
||||
void dump() const |
||||
{ |
||||
const size_t N = op_.N; |
||||
for (size_t i = 0; i < N; i++) { |
||||
printf("%016llx ", (long long)v_[N - 1 - i]); |
||||
} |
||||
printf("\n"); |
||||
} |
||||
static inline void setModulo(const std::string& mstr, int base = 0) |
||||
{ |
||||
bool isMinus; |
||||
mpz_class mp; |
||||
inFromStr(mp, &isMinus, mstr, base); |
||||
if (isMinus) throw cybozu::Exception("mcl:FpT:setModulo:mstr is not minus") << mstr; |
||||
pBitLen_ = Gmp::getBitLen(mp); |
||||
if (pBitLen_ > maxBitN) throw cybozu::Exception("mcl:FpT:setModulo:too large bitLen") << pBitLen_ << maxBitN; |
||||
Unit p[maxUnitN] = {}; |
||||
const size_t n = Gmp::getRaw(p, maxUnitN, mp); |
||||
if (n == 0) throw cybozu::Exception("mcl:FpT:setModulo:bad mstr") << mstr; |
||||
#ifdef USE_MONT_FP |
||||
if (pBitLen_ <= 128) { op_ = fp::MontFp<tag, 128>::init(p); } |
||||
#if CYBOZU_OS_BIT == 32 |
||||
else if (pBitLen_ <= 160) { static fp::MontFp<tag, 160> f; op_ = f.init(p); } |
||||
#endif |
||||
else if (pBitLen_ <= 192) { static fp::MontFp<tag, 192> f; op_ = f.init(p); } |
||||
#if CYBOZU_OS_BIT == 32 |
||||
else if (pBitLen_ <= 224) { static fp::MontFp<tag, 224> f; op_ = f.init(p); } |
||||
#endif |
||||
else if (pBitLen_ <= 256) { static fp::MontFp<tag, 256> f; op_ = f.init(p); } |
||||
else if (pBitLen_ <= 384) { static fp::MontFp<tag, 384> f; op_ = f.init(p); } |
||||
else if (pBitLen_ <= 448) { static fp::MontFp<tag, 448> f; op_ = f.init(p); } |
||||
#if CYBOZU_OS_BIT == 32 |
||||
else if (pBitLen_ <= 544) { static fp::MontFp<tag, 544> f; op_ = f.init(p); } |
||||
#else |
||||
else if (pBitLen_ <= 576) { static fp::MontFp<tag, 576> f; op_ = f.init(p); } |
||||
#endif |
||||
else { static fp::MontFp<tag, maxBitN> f; op_ = f.init(p); } |
||||
#else |
||||
if (pBitLen_ <= 128) { op_ = fp::FixedFp<tag, 128>::init(p); } |
||||
#if CYBOZU_OS_BIT == 32 |
||||
else if (pBitLen_ <= 160) { static fp::FixedFp<tag, 160> f; op_ = f.init(p); } |
||||
#endif |
||||
else if (pBitLen_ <= 192) { static fp::FixedFp<tag, 192> f; op_ = f.init(p); } |
||||
#if CYBOZU_OS_BIT == 32 |
||||
else if (pBitLen_ <= 224) { static fp::FixedFp<tag, 224> f; op_ = f.init(p); } |
||||
#endif |
||||
else if (pBitLen_ <= 256) { static fp::FixedFp<tag, 256> f; op_ = f.init(p); } |
||||
else if (pBitLen_ <= 384) { static fp::FixedFp<tag, 384> f; op_ = f.init(p); } |
||||
else if (pBitLen_ <= 448) { static fp::FixedFp<tag, 448> f; op_ = f.init(p); } |
||||
#if CYBOZU_OS_BIT == 32 |
||||
else if (pBitLen_ <= 544) { static fp::FixedFp<tag, 544> f; op_ = f.init(p); } |
||||
#else |
||||
else if (pBitLen_ <= 576) { static fp::FixedFp<tag, 576> f; op_ = f.init(p); } |
||||
#endif |
||||
else { static fp::FixedFp<tag, maxBitN> f; op_ = f.init(p); } |
||||
#endif |
||||
assert(op_.N <= maxUnitN); |
||||
sq_.set(mp); |
||||
} |
||||
static inline void getModulo(std::string& pstr) |
||||
{ |
||||
Gmp::toStr(pstr, op_.mp); |
||||
} |
||||
static inline bool isYodd(const FpT& x) |
||||
{ |
||||
Block b; |
||||
x.getBlock(b); |
||||
return (b.p[0] & 1) == 1; |
||||
} |
||||
static inline bool squareRoot(FpT& y, const FpT& x) |
||||
{ |
||||
mpz_class mx, my; |
||||
x.toGmp(mx); |
||||
bool b = sq_.get(my, mx); |
||||
if (!b) return false; |
||||
y.fromGmp(my); |
||||
return true; |
||||
} |
||||
FpT() {} |
||||
FpT(const FpT& x) |
||||
{ |
||||
op_.copy(v_, x.v_); |
||||
} |
||||
FpT& operator=(const FpT& x) |
||||
{ |
||||
op_.copy(v_, x.v_); |
||||
return *this; |
||||
} |
||||
void clear() |
||||
{ |
||||
op_.clear(v_); |
||||
} |
||||
FpT(int64_t x) { operator=(x); } |
||||
explicit FpT(const std::string& str, int base = 0) |
||||
{ |
||||
fromStr(str, base); |
||||
} |
||||
FpT& operator=(int64_t x) |
||||
{ |
||||
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(*this, *this); |
||||
} |
||||
return *this; |
||||
} |
||||
void toMont(FpT& y, const FpT& x) |
||||
{ |
||||
if (op_.toMont) op_.toMont(y.v_, x.v_); |
||||
} |
||||
void fromMont(FpT& y, const FpT& x) |
||||
{ |
||||
if (op_.fromMont) op_.fromMont(y.v_, x.v_); |
||||
} |
||||
void fromStr(const std::string& str, int base = 0) |
||||
{ |
||||
bool isMinus; |
||||
mpz_class x; |
||||
inFromStr(x, &isMinus, str, base); |
||||
if (x >= op_.mp) throw cybozu::Exception("fp:FpT:fromStr:large str") << str; |
||||
fp::local::toArray(v_, op_.N, x.get_mpz_t()); |
||||
if (isMinus) { |
||||
neg(*this, *this); |
||||
} |
||||
toMont(*this, *this); |
||||
} |
||||
// alias of fromStr
|
||||
void set(const std::string& str, int base = 0) { fromStr(str, base); } |
||||
template<class S> |
||||
void setRaw(const S *inBuf, size_t n) |
||||
{ |
||||
const size_t byteN = sizeof(S) * n; |
||||
const size_t fpByteN = sizeof(Unit) * op_.N; |
||||
if (byteN > fpByteN) throw cybozu::Exception("setRaw:bad n") << n << fpByteN; |
||||
assert(byteN <= fpByteN); |
||||
memcpy(v_, inBuf, byteN); |
||||
memset((char *)v_ + byteN, 0, fpByteN - byteN); |
||||
if (!isValid()) throw cybozu::Exception("setRaw:large value"); |
||||
toMont(*this, *this); |
||||
} |
||||
template<class S> |
||||
size_t getRaw(S *outBuf, size_t n) const |
||||
{ |
||||
const size_t byteN = sizeof(S) * n; |
||||
const size_t fpByteN = sizeof(Unit) * op_.N; |
||||
if (byteN < fpByteN) throw cybozu::Exception("getRaw:bad n") << n << fpByteN; |
||||
assert(byteN >= fpByteN); |
||||
Block b; |
||||
getBlock(b); |
||||
memcpy(outBuf, b.p, fpByteN); |
||||
const size_t writeN = (fpByteN + sizeof(S) - 1) / sizeof(S); |
||||
memset((char *)outBuf + fpByteN, 0, writeN * sizeof(S) - fpByteN); |
||||
return writeN; |
||||
} |
||||
void getBlock(Block& b) const |
||||
{ |
||||
assert(maxUnitN <= Block::maxUnitN); |
||||
b.n = op_.N; |
||||
if (op_.fromMont) { |
||||
op_.fromMont(b.v_, v_); |
||||
b.p = &b.v_[0]; |
||||
} else { |
||||
b.p = &v_[0]; |
||||
} |
||||
} |
||||
template<class RG> |
||||
void setRand(RG& rg) |
||||
{ |
||||
fp::getRandVal(v_, rg, op_.p, pBitLen_); |
||||
fromMont(*this, *this); |
||||
} |
||||
static inline void toStr(std::string& str, const Unit *x, size_t n, int base = 10, bool withPrefix = false) |
||||
{ |
||||
switch (base) { |
||||
case 10: |
||||
{ |
||||
mpz_class t; |
||||
Gmp::setRaw(t, x, n); |
||||
Gmp::toStr(str, t, 10); |
||||
} |
||||
return; |
||||
case 16: |
||||
mcl::fp::toStr16(str, x, n, withPrefix); |
||||
return; |
||||
case 2: |
||||
mcl::fp::toStr2(str, x, n, withPrefix); |
||||
return; |
||||
default: |
||||
throw cybozu::Exception("fp:FpT:toStr:bad base") << base; |
||||
} |
||||
} |
||||
void toStr(std::string& str, int base = 10, bool withPrefix = false) const |
||||
{ |
||||
Block b; |
||||
getBlock(b); |
||||
toStr(str, b.p, b.n, base, withPrefix); |
||||
} |
||||
std::string toStr(int base = 10, bool withPrefix = false) const |
||||
{ |
||||
std::string str; |
||||
toStr(str, base, withPrefix); |
||||
return str; |
||||
} |
||||
void toGmp(mpz_class& x) const |
||||
{ |
||||
Block b; |
||||
getBlock(b); |
||||
Gmp::setRaw(x, b.p, b.n); |
||||
} |
||||
mpz_class toGmp() const |
||||
{ |
||||
mpz_class x; |
||||
toGmp(x); |
||||
return x; |
||||
} |
||||
void fromGmp(const mpz_class& x) |
||||
{ |
||||
setRaw(Gmp::getBlock(x), Gmp::getBlockSize(x)); |
||||
} |
||||
static inline void add(FpT& z, const FpT& x, const FpT& y) { op_.add(z.v_, x.v_, y.v_); } |
||||
static inline void sub(FpT& z, const FpT& x, const FpT& y) { op_.sub(z.v_, x.v_, y.v_); } |
||||
static inline void mul(FpT& z, const FpT& x, const FpT& y) { op_.mul(z.v_, x.v_, y.v_); } |
||||
static inline void inv(FpT& y, const FpT& x) { op_.inv(y.v_, x.v_); } |
||||
static inline void neg(FpT& y, const FpT& x) { op_.neg(y.v_, x.v_); } |
||||
static inline void square(FpT& y, const FpT& x) { op_.square(y.v_, x.v_); } |
||||
static inline void div(FpT& z, const FpT& x, const FpT& y) |
||||
{ |
||||
FpT rev; |
||||
inv(rev, y); |
||||
mul(z, x, rev); |
||||
} |
||||
static inline void powerArray(FpT& z, const FpT& x, const Unit *y, size_t yn) |
||||
{ |
||||
FpT out(1); |
||||
FpT t(x); |
||||
for (size_t i = 0; i < yn; i++) { |
||||
const Unit v = y[i]; |
||||
int m = (int)sizeof(Unit) * 8; |
||||
if (i == yn - 1) { |
||||
while (m > 0 && (v & (Unit(1) << (m - 1))) == 0) { |
||||
m--; |
||||
} |
||||
} |
||||
for (int j = 0; j < m; j++) { |
||||
if (v & (Unit(1) << j)) { |
||||
out *= t; |
||||
} |
||||
t *= t; |
||||
} |
||||
} |
||||
z = out; |
||||
} |
||||
template<class tag2, size_t maxBitN2> |
||||
static inline void power(FpT& z, const FpT& x, const FpT<tag2, maxBitN2>& y) |
||||
{ |
||||
Block b; |
||||
y.getBlock(b); |
||||
powerArray(z, x, b.p, b.n); |
||||
} |
||||
static inline void power(FpT& z, const FpT& x, int y) |
||||
{ |
||||
if (y < 0) throw cybozu::Exception("FpT:power with negative y is not support") << y; |
||||
const Unit u = y; |
||||
powerArray(z, x, &u, 1); |
||||
} |
||||
static inline void power(FpT& z, const FpT& x, const mpz_class& y) |
||||
{ |
||||
if (y < 0) throw cybozu::Exception("FpT:power with negative y is not support") << y; |
||||
powerArray(z, x, Gmp::getBlock(y), Gmp::getBlockSize(x)); |
||||
} |
||||
bool isZero() const { return op_.isZero(v_); } |
||||
/*
|
||||
append to bv(not clear bv) |
||||
*/ |
||||
void appendToBitVec(cybozu::BitVector& bv) const |
||||
{ |
||||
Block b; |
||||
getBlock(b); |
||||
bv.append(b.p, pBitLen_); |
||||
} |
||||
bool isValid() const |
||||
{ |
||||
return fp::local::compareArray(v_, op_.p, op_.N) < 0; |
||||
} |
||||
void fromBitVec(const cybozu::BitVector& bv) |
||||
{ |
||||
if (bv.size() != pBitLen_) throw cybozu::Exception("FpT:fromBitVec:bad size") << bv.size() << pBitLen_; |
||||
setRaw(bv.getBlock(), bv.getBlockSize()); |
||||
} |
||||
static inline size_t getModBitLen() { return pBitLen_; } |
||||
static inline size_t getBitVecSize() { return pBitLen_; } |
||||
bool operator==(const FpT& rhs) const { return fp::local::isEqualArray(v_, rhs.v_, op_.N); } |
||||
bool operator!=(const FpT& rhs) const { return !operator==(rhs); } |
||||
inline friend FpT operator+(const FpT& x, const FpT& y) { FpT z; add(z, x, y); return z; } |
||||
inline friend FpT operator-(const FpT& x, const FpT& y) { FpT z; sub(z, x, y); return z; } |
||||
inline friend FpT operator*(const FpT& x, const FpT& y) { FpT z; mul(z, x, y); return z; } |
||||
inline friend FpT operator/(const FpT& x, const FpT& y) { FpT z; div(z, x, y); return z; } |
||||
FpT& operator+=(const FpT& x) { add(*this, *this, x); return *this; } |
||||
FpT& operator-=(const FpT& x) { sub(*this, *this, x); return *this; } |
||||
FpT& operator*=(const FpT& x) { mul(*this, *this, x); return *this; } |
||||
FpT& operator/=(const FpT& x) { div(*this, *this, x); return *this; } |
||||
FpT operator-() const { FpT x; neg(x, *this); return x; } |
||||
friend inline std::ostream& operator<<(std::ostream& os, const FpT& self) |
||||
{ |
||||
const std::ios_base::fmtflags f = os.flags(); |
||||
if (f & std::ios_base::oct) throw cybozu::Exception("fpT:operator<<:oct is not supported"); |
||||
const int base = (f & std::ios_base::hex) ? 16 : 10; |
||||
const bool showBase = (f & std::ios_base::showbase) != 0; |
||||
std::string str; |
||||
self.toStr(str, base, showBase); |
||||
return os << str; |
||||
} |
||||
friend inline std::istream& operator>>(std::istream& is, FpT& self) |
||||
{ |
||||
const std::ios_base::fmtflags f = is.flags(); |
||||
if (f & std::ios_base::oct) throw cybozu::Exception("fpT:operator>>:oct is not supported"); |
||||
const int base = (f & std::ios_base::hex) ? 16 : 0; |
||||
std::string str; |
||||
is >> str; |
||||
self.fromStr(str, base); |
||||
return is; |
||||
} |
||||
/*
|
||||
not support |
||||
getBitLen, operator<, > |
||||
*/ |
||||
/*
|
||||
QQQ : should be removed |
||||
*/ |
||||
bool operator<(const FpT&) const { return false; } |
||||
static inline int compare(const FpT& x, const FpT& y) |
||||
{ |
||||
Block xb, yb; |
||||
x.getBlock(xb); |
||||
y.getBlock(yb); |
||||
return fp::local::compareArray(xb.p, yb.p, xb.n); |
||||
} |
||||
private: |
||||
static inline void inFromStr(mpz_class& x, bool *isMinus, const std::string& str, int base) |
||||
{ |
||||
const char *p = fp::verifyStr(isMinus, &base, str); |
||||
if (!Gmp::fromStr(x, p, base)) { |
||||
throw cybozu::Exception("fp:FpT:inFromStr") << str; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
template<class tag, size_t maxBitN> fp::Op FpT<tag, maxBitN>::op_; |
||||
template<class tag, size_t maxBitN> mcl::SquareRoot FpT<tag, maxBitN>::sq_; |
||||
template<class tag, size_t maxBitN> size_t FpT<tag, maxBitN>::pBitLen_; |
||||
|
||||
namespace power_impl { |
||||
|
||||
template<class G, class tag, size_t bitN, template<class _tag, size_t _bitN>class FpT> |
||||
void power(G& z, const G& x, const FpT<tag, bitN>& y) |
||||
{ |
||||
Block b; |
||||
y.getBlock(b); |
||||
mcl::power_impl::powerArray(z, x, b.p, b.n); |
||||
} |
||||
|
||||
} // mcl::power_impl
|
||||
} // mcl
|
||||
|
||||
namespace std { CYBOZU_NAMESPACE_TR1_BEGIN |
||||
template<class T> struct hash; |
||||
|
||||
template<class tag, size_t maxBitN> |
||||
struct hash<mcl::FpT<tag, maxBitN> > : public std::unary_function<mcl::FpT<tag, maxBitN>, size_t> { |
||||
size_t operator()(const mcl::FpT<tag, maxBitN>& x, uint64_t v = 0) const |
||||
{ |
||||
return static_cast<size_t>(cybozu::hash64(x.getUnit(), x.getUnitN(), v)); |
||||
} |
||||
}; |
||||
|
||||
CYBOZU_NAMESPACE_TR1_END } // std::tr1
|
||||
|
||||
#ifdef _WIN32 |
||||
#pragma warning(pop) |
||||
#endif |
@ -0,0 +1,527 @@ |
||||
#pragma once |
||||
/**
|
||||
@file |
||||
@brief basic operation |
||||
@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 : 4616) |
||||
#pragma warning(disable : 4800) |
||||
#pragma warning(disable : 4244) |
||||
#pragma warning(disable : 4127) |
||||
#pragma warning(disable : 4512) |
||||
#pragma warning(disable : 4146) |
||||
#endif |
||||
#include <stdint.h> |
||||
#include <assert.h> |
||||
#include <mcl/gmp_util.hpp> |
||||
#ifdef _MSC_VER |
||||
#pragma warning(pop) |
||||
#endif |
||||
#include <cybozu/inttype.hpp> |
||||
#ifdef USE_MONT_FP |
||||
#include <mcl/fp_generator.hpp> |
||||
#endif |
||||
|
||||
namespace mcl { namespace fp { |
||||
|
||||
#if defined(CYBOZU_OS_BIT) && (CYBOZU_OS_BIT == 32) |
||||
typedef uint32_t Unit; |
||||
#else |
||||
typedef uint64_t Unit; |
||||
#endif |
||||
|
||||
typedef void (*void1op)(Unit*); |
||||
typedef void (*void2op)(Unit*, const Unit*); |
||||
typedef void (*void3op)(Unit*, const Unit*, const Unit*); |
||||
typedef void (*void4op)(Unit*, const Unit*, const Unit*, const Unit*); |
||||
typedef int (*int2op)(Unit*, const Unit*); |
||||
typedef void (*void4Iop)(Unit*, const Unit*, const Unit*, const Unit*, Unit); |
||||
|
||||
} } // mcl::fp
|
||||
|
||||
#ifdef MCL_USE_LLVM |
||||
|
||||
extern "C" { |
||||
|
||||
#define MCL_FP_DEF_FUNC(len) \ |
||||
void mcl_fp_add ## len ## S(mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*); \
|
||||
void mcl_fp_add ## len ## L(mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*); \
|
||||
void mcl_fp_sub ## len ## S(mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*); \
|
||||
void mcl_fp_sub ## len ## L(mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*); \
|
||||
void mcl_fp_mul ## len ## pre(mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*); \
|
||||
void mcl_fp_mont ## len(mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*, mcl::fp::Unit); |
||||
|
||||
MCL_FP_DEF_FUNC(128) |
||||
MCL_FP_DEF_FUNC(192) |
||||
MCL_FP_DEF_FUNC(256) |
||||
MCL_FP_DEF_FUNC(320) |
||||
MCL_FP_DEF_FUNC(384) |
||||
MCL_FP_DEF_FUNC(448) |
||||
MCL_FP_DEF_FUNC(512) |
||||
#if CYBOZU_OS_BIT == 32 |
||||
MCL_FP_DEF_FUNC(160) |
||||
MCL_FP_DEF_FUNC(224) |
||||
MCL_FP_DEF_FUNC(288) |
||||
MCL_FP_DEF_FUNC(352) |
||||
MCL_FP_DEF_FUNC(416) |
||||
MCL_FP_DEF_FUNC(480) |
||||
MCL_FP_DEF_FUNC(544) |
||||
#else |
||||
MCL_FP_DEF_FUNC(576) |
||||
#endif |
||||
|
||||
void mcl_fp_mul_NIST_P192(mcl::fp::Unit*, const mcl::fp::Unit*, const mcl::fp::Unit*); |
||||
|
||||
} |
||||
|
||||
#endif |
||||
|
||||
namespace mcl { namespace fp { |
||||
|
||||
namespace local { |
||||
|
||||
inline int compareArray(const Unit* x, const Unit* y, size_t n) |
||||
{ |
||||
for (size_t i = n - 1; i != size_t(-1); i--) { |
||||
if (x[i] < y[i]) return -1; |
||||
if (x[i] > y[i]) return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
inline bool isEqualArray(const Unit* x, const Unit* y, size_t n) |
||||
{ |
||||
for (size_t i = 0; i < n; i++) { |
||||
if (x[i] != y[i]) return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
inline bool isZeroArray(const Unit *x, size_t n) |
||||
{ |
||||
for (size_t i = 0; i < n; i++) { |
||||
if (x[i]) return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
inline void clearArray(Unit *x, size_t begin, size_t end) |
||||
{ |
||||
for (size_t i = begin; i < end; i++) x[i] = 0; |
||||
} |
||||
|
||||
inline void copyArray(Unit *y, const Unit *x, size_t n) |
||||
{ |
||||
for (size_t i = 0; i < n; i++) y[i] = x[i]; |
||||
} |
||||
|
||||
inline void toArray(Unit *y, size_t yn, const mpz_srcptr x) |
||||
{ |
||||
const int xn = x->_mp_size; |
||||
assert(xn >= 0); |
||||
const Unit* xp = (const Unit*)x->_mp_d; |
||||
assert(xn <= (int)yn); |
||||
copyArray(y, xp, xn); |
||||
clearArray(y, xn, yn); |
||||
} |
||||
|
||||
} // mcl::fp
|
||||
struct TagDefault; |
||||
|
||||
struct Op { |
||||
mpz_class mp; |
||||
const Unit* p; |
||||
size_t N; |
||||
bool (*isZero)(const Unit*); |
||||
void1op clear; |
||||
void2op neg; |
||||
void2op inv; |
||||
void2op square; |
||||
void2op copy; |
||||
void3op add; |
||||
void3op sub; |
||||
void3op mul; |
||||
// for Montgomery
|
||||
void2op toMont; |
||||
void2op fromMont; |
||||
Op() |
||||
: p(0), N(0), isZero(0), clear(0), neg(0), inv(0) |
||||
, square(0), copy(0),add(0), sub(0), mul(0), toMont(0), fromMont(0) |
||||
{ |
||||
} |
||||
}; |
||||
|
||||
template<class tag, size_t bitN> |
||||
struct FixedFp { |
||||
typedef fp::Unit Unit; |
||||
static const size_t N = (bitN + sizeof(Unit) * 8 - 1) / (sizeof(Unit) * 8); |
||||
static mpz_class mp_; |
||||
static Unit p_[N]; |
||||
static inline void setModulo(const Unit* p) |
||||
{ |
||||
assert(N >= 2); |
||||
assert(sizeof(mp_limb_t) == sizeof(Unit)); |
||||
copy(p_, p); |
||||
Gmp::setRaw(mp_, p, N); |
||||
} |
||||
static inline void set_mpz_t(mpz_t& z, const Unit* p, int n = (int)N) |
||||
{ |
||||
z->_mp_alloc = n; |
||||
int i = n; |
||||
while (i > 0 && p[i - 1] == 0) { |
||||
i--; |
||||
} |
||||
z->_mp_size = i; |
||||
z->_mp_d = (mp_limb_t*)const_cast<Unit*>(p); |
||||
} |
||||
static inline void set_zero(mpz_t& z, Unit *p, size_t n) |
||||
{ |
||||
z->_mp_alloc = (int)n; |
||||
z->_mp_size = 0; |
||||
z->_mp_d = (mp_limb_t*)p; |
||||
} |
||||
static inline void clear(Unit *x) |
||||
{ |
||||
local::clearArray(x, 0, N); |
||||
} |
||||
static inline void copy(Unit *y, const Unit *x) |
||||
{ |
||||
local::copyArray(y, x, N); |
||||
} |
||||
static inline void add(Unit *z, const Unit *x, const Unit *y) |
||||
{ |
||||
Unit ret[N + 2]; // not N + 1
|
||||
mpz_t mz, mx, my; |
||||
set_zero(mz, ret, N + 2); |
||||
set_mpz_t(mx, x); |
||||
set_mpz_t(my, y); |
||||
mpz_add(mz, mx, my); |
||||
if (mpz_cmp(mz, mp_.get_mpz_t()) >= 0) { |
||||
mpz_sub(mz, mz, mp_.get_mpz_t()); |
||||
} |
||||
local::toArray(z, N, mz); |
||||
} |
||||
#ifdef MCL_USE_LLVM |
||||
#if CYBOZU_OS_BIT == 64 |
||||
static inline void add128(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add128S(z, x, y, p_); } |
||||
static inline void sub128(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub128S(z, x, y, p_); } |
||||
static inline void add192(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add192S(z, x, y, p_); } |
||||
static inline void sub192(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub192S(z, x, y, p_); } |
||||
static inline void add256(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add256S(z, x, y, p_); } |
||||
static inline void sub256(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub256S(z, x, y, p_); } |
||||
static inline void add384(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add384L(z, x, y, p_); } |
||||
static inline void sub384(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub384L(z, x, y, p_); } |
||||
|
||||
static inline void add576(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add576L(z, x, y, p_); } |
||||
static inline void sub576(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub576L(z, x, y, p_); } |
||||
#else |
||||
static inline void add128(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add128S(z, x, y, p_); } |
||||
static inline void sub128(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub128S(z, x, y, p_); } |
||||
static inline void add192(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add192L(z, x, y, p_); } |
||||
static inline void sub192(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub192L(z, x, y, p_); } |
||||
static inline void add256(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add256L(z, x, y, p_); } |
||||
static inline void sub256(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub256L(z, x, y, p_); } |
||||
static inline void add384(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add384L(z, x, y, p_); } |
||||
static inline void sub384(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub384L(z, x, y, p_); } |
||||
|
||||
static inline void add160(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add160L(z, x, y, p_); } |
||||
static inline void sub160(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub160L(z, x, y, p_); } |
||||
static inline void add224(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add224L(z, x, y, p_); } |
||||
static inline void sub224(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub224L(z, x, y, p_); } |
||||
static inline void add544(Unit *z, const Unit *x, const Unit *y) { mcl_fp_add544L(z, x, y, p_); } |
||||
static inline void sub544(Unit *z, const Unit *x, const Unit *y) { mcl_fp_sub544L(z, x, y, p_); } |
||||
#endif |
||||
#endif |
||||
static inline void sub(Unit *z, const Unit *x, const Unit *y) |
||||
{ |
||||
Unit ret[N + 1]; |
||||
mpz_t mz, mx, my; |
||||
set_zero(mz, ret, N + 1); |
||||
set_mpz_t(mx, x); |
||||
set_mpz_t(my, y); |
||||
mpz_sub(mz, mx, my); |
||||
if (mpz_sgn(mz) < 0) { |
||||
mpz_add(mz, mz, mp_.get_mpz_t()); |
||||
} |
||||
local::toArray(z, N, mz); |
||||
} |
||||
static inline void mul(Unit *z, const Unit *x, const Unit *y) |
||||
{ |
||||
Unit ret[N * 2]; |
||||
#ifdef MCL_USE_LLVM |
||||
#if CYBOZU_OS_BIT == 64 |
||||
if (bitN <= 128) { mcl_fp_mul128pre(ret, x, y); mod(z, ret); return; } |
||||
if (bitN <= 192) { mcl_fp_mul192pre(ret, x, y); mod(z, ret); return; } |
||||
if (bitN <= 256) { mcl_fp_mul256pre(ret, x, y); mod(z, ret); return; } |
||||
if (bitN <= 384) { mcl_fp_mul384pre(ret, x, y); mod(z, ret); return; } |
||||
// if (bitN <= 576) { mcl_fp_mul576pre(ret, x, y); mod(z, ret); return; }
|
||||
#else |
||||
if (bitN <= 128) { mcl_fp_mul128pre(ret, x, y); mod(z, ret); return; } |
||||
if (bitN <= 160) { mcl_fp_mul160pre(ret, x, y); mod(z, ret); return; } |
||||
if (bitN <= 192) { mcl_fp_mul192pre(ret, x, y); mod(z, ret); return; } |
||||
if (bitN <= 224) { mcl_fp_mul224pre(ret, x, y); mod(z, ret); return; } |
||||
// if (bitN <= 256) { mcl_fp_mul256pre(ret, x, y); mod(z, ret); return; }
|
||||
// if (bitN <= 384) { mcl_fp_mul384pre(ret, x, y); mod(z, ret); return; }
|
||||
// if (bitN <= 544) { mcl_fp_mul544pre(ret, x, y); mod(z, ret); return; }
|
||||
#endif |
||||
#endif |
||||
#if 0 |
||||
pre_mul(ret, x, y); |
||||
mod(z, ret); |
||||
#else |
||||
mpz_t mx, my, mz; |
||||
set_zero(mz, ret, N * 2); |
||||
set_mpz_t(mx, x); |
||||
set_mpz_t(my, y); |
||||
mpz_mul(mz, mx, my); |
||||
mpz_mod(mz, mz, mp_.get_mpz_t()); |
||||
local::toArray(z, N, mz); |
||||
#endif |
||||
} |
||||
static inline void pre_mul(Unit *z, const Unit *x, const Unit *y) |
||||
{ |
||||
mpz_t mx, my, mz; |
||||
set_zero(mz, z, N * 2); |
||||
set_mpz_t(mx, x); |
||||
set_mpz_t(my, y); |
||||
mpz_mul(mz, mx, my); |
||||
local::toArray(z, N * 2, mz); |
||||
} |
||||
// x[N * 2] -> y[N]
|
||||
static inline void mod(Unit *y, const Unit *x) |
||||
{ |
||||
mpz_t mx, my; |
||||
set_mpz_t(mx, x, N * 2); |
||||
set_mpz_t(my, y, N); |
||||
mpz_mod(my, mx, mp_.get_mpz_t()); |
||||
local::clearArray(y, my->_mp_size, N); |
||||
} |
||||
static inline void square(Unit *z, const Unit *x) |
||||
{ |
||||
mul(z, x, x); // QQQ : use powMod with 2?
|
||||
} |
||||
static inline void inv(Unit *y, const Unit *x) |
||||
{ |
||||
mpz_class my; |
||||
mpz_t mx; |
||||
set_mpz_t(mx, x); |
||||
mpz_invert(my.get_mpz_t(), mx, mp_.get_mpz_t()); |
||||
local::toArray(y, N, my.get_mpz_t()); |
||||
} |
||||
static inline bool isZero(const Unit *x) |
||||
{ |
||||
return local::isZeroArray(x, N); |
||||
} |
||||
static inline void neg(Unit *y, const Unit *x) |
||||
{ |
||||
if (isZero(x)) { |
||||
if (x != y) clear(y); |
||||
return; |
||||
} |
||||
sub(y, p_, x); |
||||
} |
||||
static inline Op init(const Unit *p) |
||||
{ |
||||
setModulo(p); |
||||
Op op; |
||||
op.N = N; |
||||
op.isZero = &isZero; |
||||
op.clear = &clear; |
||||
op.neg = &neg; |
||||
op.inv = &inv; |
||||
op.square = □ |
||||
op.copy = © |
||||
#ifdef MCL_USE_LLVM |
||||
printf("fp2 use llvm bitN=%zd\n", bitN); |
||||
if (bitN <= 128) { |
||||
op.add = &add128; |
||||
op.sub = &sub128; |
||||
} else |
||||
#if CYBOZU_OS_BIT == 32 |
||||
if (bitN <= 160) { |
||||
op.add = &add160; |
||||
op.sub = &sub160; |
||||
} else |
||||
#endif |
||||
if (bitN <= 192) { |
||||
op.add = &add192; |
||||
op.sub = &sub192; |
||||
} else |
||||
#if CYBOZU_OS_BIT == 32 |
||||
if (bitN <= 224) { |
||||
op.add = &add224; |
||||
op.sub = &sub224; |
||||
} else |
||||
#endif |
||||
if (bitN <= 256) { |
||||
op.add = &add256; |
||||
op.sub = &sub256; |
||||
} else |
||||
if (bitN <= 384) { |
||||
op.add = &add384; |
||||
op.sub = &sub384; |
||||
} else |
||||
#if CYBOZU_OS_BIT == 64 |
||||
if (bitN <= 576) { |
||||
op.add = &add576; |
||||
op.sub = &sub576; |
||||
} else |
||||
#else |
||||
if (bitN <= 544) { |
||||
op.add = &add544; |
||||
op.sub = &sub544; |
||||
} else |
||||
#endif |
||||
#endif |
||||
{ |
||||
op.add = &add; |
||||
op.sub = ⊂ |
||||
} |
||||
#ifdef MCL_USE_LLVM |
||||
if (mp_ == mpz_class("0xfffffffffffffffffffffffffffffffeffffffffffffffff")) { |
||||
op.mul = &mcl_fp_mul_NIST_P192; // slower than MontFp192
|
||||
} else |
||||
#endif |
||||
{ |
||||
op.mul = &mul; |
||||
} |
||||
op.mp = mp_; |
||||
op.p = &p_[0]; |
||||
return op; |
||||
} |
||||
}; |
||||
|
||||
template<class tag, size_t bitN> mpz_class FixedFp<tag, bitN>::mp_; |
||||
template<class tag, size_t bitN> fp::Unit FixedFp<tag, bitN>::p_[FixedFp<tag, bitN>::N]; |
||||
|
||||
#ifdef USE_MONT_FP |
||||
template<class tag, size_t bitN> |
||||
struct MontFp { |
||||
typedef fp::Unit Unit; |
||||
static const size_t N = (bitN + sizeof(Unit) * 8 - 1) / (sizeof(Unit) * 8); |
||||
static const size_t invTblN = N * sizeof(Unit) * 8 * 2; |
||||
static mpz_class mp_; |
||||
// static mcl::SquareRoot sq_;
|
||||
static Unit p_[N]; |
||||
static Unit one_[N]; |
||||
static Unit R_[N]; // (1 << (N * 64)) % p
|
||||
static Unit RR_[N]; // (R * R) % p
|
||||
static Unit invTbl_[invTblN][N]; |
||||
static size_t modBitLen_; |
||||
static FpGenerator fg_; |
||||
static void3op add_; |
||||
static void3op mul_; |
||||
|
||||
static inline void fromRawGmp(Unit *y, const mpz_class& x) |
||||
{ |
||||
local::toArray(y, N, x.get_mpz_t()); |
||||
} |
||||
static inline void setModulo(const Unit *p) |
||||
{ |
||||
copy(p_, p); |
||||
Gmp::setRaw(mp_, p, N); |
||||
// sq_.set(pOrg_);
|
||||
|
||||
mpz_class t = 1; |
||||
fromRawGmp(one_, t); |
||||
t = (t << (N * 64)) % mp_; |
||||
fromRawGmp(R_, t); |
||||
t = (t * t) % mp_; |
||||
fromRawGmp(RR_, t); |
||||
fg_.init(p_, N); |
||||
|
||||
add_ = Xbyak::CastTo<void3op>(fg_.add_); |
||||
mul_ = Xbyak::CastTo<void3op>(fg_.mul_); |
||||
} |
||||
static void initInvTbl(Unit invTbl[invTblN][N]) |
||||
{ |
||||
Unit t[N]; |
||||
clear(t); |
||||
t[0] = 2; |
||||
toMont(t, t); |
||||
for (int i = 0; i < invTblN; i++) { |
||||
copy(invTbl[invTblN - 1 - i], t); |
||||
add_(t, t, t); |
||||
} |
||||
} |
||||
static inline void clear(Unit *x) |
||||
{ |
||||
local::clearArray(x, 0, N); |
||||
} |
||||
static inline void copy(Unit *y, const Unit *x) |
||||
{ |
||||
local::copyArray(y, x, N); |
||||
} |
||||
static inline bool isZero(const Unit *x) |
||||
{ |
||||
return local::isZeroArray(x, N); |
||||
} |
||||
static inline void invC(Unit *y, const Unit *x) |
||||
{ |
||||
const int2op preInv = Xbyak::CastTo<int2op>(fg_.preInv_); |
||||
Unit r[N]; |
||||
int k = preInv(r, x); |
||||
/*
|
||||
xr = 2^k |
||||
R = 2^(N * 64) |
||||
get r2^(-k)R^2 = r 2^(N * 64 * 2 - k) |
||||
*/ |
||||
mul_(y, r, invTbl_[k]); |
||||
} |
||||
static inline void squareC(Unit *y, const Unit *x) |
||||
{ |
||||
mul_(y, x, x); |
||||
} |
||||
static inline void toMont(Unit *y, const Unit *x) |
||||
{ |
||||
mul_(y, x, RR_); |
||||
} |
||||
static inline void fromMont(Unit *y, const Unit *x) |
||||
{ |
||||
mul_(y, x, one_); |
||||
} |
||||
static inline Op init(const Unit *p) |
||||
{ |
||||
puts("use MontFp2"); |
||||
setModulo(p); |
||||
Op op; |
||||
op.N = N; |
||||
op.isZero = &isZero; |
||||
op.clear = &clear; |
||||
op.neg = Xbyak::CastTo<void2op>(fg_.neg_); |
||||
op.inv = &invC; |
||||
op.square = Xbyak::CastTo<void2op>(fg_.sqr_); |
||||
if (op.square == 0) op.square = &squareC; |
||||
op.copy = © |
||||
op.add = add_; |
||||
op.sub = Xbyak::CastTo<void3op>(fg_.sub_); |
||||
op.mul = mul_; |
||||
op.mp = mp_; |
||||
op.p = &p_[0]; |
||||
op.toMont = &toMont; |
||||
op.fromMont = &fromMont; |
||||
|
||||
// shr1 = Xbyak::CastTo<void2op>(fg_.shr1_);
|
||||
// addNc = Xbyak::CastTo<bool3op>(fg_.addNc_);
|
||||
// subNc = Xbyak::CastTo<bool3op>(fg_.subNc_);
|
||||
initInvTbl(invTbl_); |
||||
return op; |
||||
} |
||||
}; |
||||
template<class tag, size_t bitN> mpz_class MontFp<tag, bitN>::mp_; |
||||
template<class tag, size_t bitN> fp::Unit MontFp<tag, bitN>::p_[MontFp<tag, bitN>::N]; |
||||
template<class tag, size_t bitN> fp::Unit MontFp<tag, bitN>::one_[MontFp<tag, bitN>::N]; |
||||
template<class tag, size_t bitN> fp::Unit MontFp<tag, bitN>::R_[MontFp<tag, bitN>::N]; |
||||
template<class tag, size_t bitN> fp::Unit MontFp<tag, bitN>::RR_[MontFp<tag, bitN>::N]; |
||||
template<class tag, size_t bitN> fp::Unit MontFp<tag, bitN>::invTbl_[MontFp<tag, bitN>::invTblN][MontFp<tag, bitN>::N]; |
||||
template<class tag, size_t bitN> size_t MontFp<tag, bitN>::modBitLen_; |
||||
template<class tag, size_t bitN> FpGenerator MontFp<tag, bitN>::fg_; |
||||
template<class tag, size_t bitN> void3op MontFp<tag, bitN>::add_; |
||||
template<class tag, size_t bitN> void3op MontFp<tag, bitN>::mul_; |
||||
#endif |
||||
|
||||
} } // mcl::fp
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,294 @@ |
||||
#pragma once |
||||
#include <vector> |
||||
#include <cybozu/itoa.hpp> |
||||
#include <cybozu/atoi.hpp> |
||||
#include <cybozu/bitvector.hpp> |
||||
/**
|
||||
@file |
||||
@brief utility of Fp |
||||
@author MITSUNARI Shigeo(@herumi) |
||||
@license modified new BSD license |
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
*/ |
||||
|
||||
namespace mcl { namespace fp { |
||||
|
||||
#if defined(CYBOZU_OS_BIT) && (CYBOZU_OS_BIT == 32) |
||||
typedef uint32_t BlockType; |
||||
#else |
||||
typedef uint64_t BlockType; |
||||
#endif |
||||
|
||||
template<class S> |
||||
void setBlockBit(S *buf, size_t bitLen, bool b) |
||||
{ |
||||
const size_t unitSize = sizeof(S) * 8; |
||||
const size_t q = bitLen / unitSize; |
||||
const size_t r = bitLen % unitSize; |
||||
if (b) { |
||||
buf[q] |= S(1) << r; |
||||
} else { |
||||
buf[q] &= ~(S(1) << r); |
||||
} |
||||
} |
||||
template<class S> |
||||
bool getBlockBit(const S *buf, size_t bitLen) |
||||
{ |
||||
const size_t unitSize = sizeof(S) * 8; |
||||
const size_t q = bitLen / unitSize; |
||||
const size_t r = bitLen % unitSize; |
||||
return (buf[q] & (S(1) << r)) != 0; |
||||
} |
||||
/*
|
||||
convert x[0..n) to hex string |
||||
start "0x" if withPrefix |
||||
*/ |
||||
template<class T> |
||||
void toStr16(std::string& str, 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; |
||||
str.resize(startPos + fullN * lenT + topLen); |
||||
if (withPrefix) { |
||||
str[0] = '0'; |
||||
str[1] = 'x'; |
||||
} |
||||
cybozu::itohex(&str[startPos], topLen, v, false); |
||||
for (size_t i = 0; i < fullN; i++) { |
||||
cybozu::itohex(&str[startPos + topLen + i * lenT], lenT, x[fullN - 1 - i], false); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
convert x[0..n) to bin string |
||||
start "0b" if withPrefix |
||||
*/ |
||||
template<class T> |
||||
void toStr2(std::string& str, 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; |
||||
str.resize(startPos + fullN * lenT + topLen); |
||||
if (withPrefix) { |
||||
str[0] = '0'; |
||||
str[1] = 'b'; |
||||
} |
||||
cybozu::itobin(&str[startPos], topLen, v); |
||||
for (size_t i = 0; i < fullN; i++) { |
||||
cybozu::itobin(&str[startPos + topLen + i * lenT], lenT, x[fullN - 1 - i]); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
convert hex string to x[0..xn) |
||||
hex string = [0-9a-fA-F]+ |
||||
*/ |
||||
template<class T> |
||||
void fromStr16(T *x, size_t xn, const char *str, size_t strLen) |
||||
{ |
||||
if (strLen == 0) throw cybozu::Exception("fp:fromStr16:strLen is zero"); |
||||
const size_t unitLen = sizeof(T) * 2; |
||||
const size_t q = strLen / unitLen; |
||||
const size_t r = strLen % unitLen; |
||||
const size_t requireSize = q + (r ? 1 : 0); |
||||
if (xn < requireSize) throw cybozu::Exception("fp:fromStr16:short size") << xn << requireSize; |
||||
for (size_t i = 0; i < q; i++) { |
||||
bool b; |
||||
x[i] = cybozu::hextoi(&b, &str[r + (q - 1 - i) * unitLen], unitLen); |
||||
if (!b) throw cybozu::Exception("fp:fromStr16:bad char") << cybozu::exception::makeString(str, strLen); |
||||
} |
||||
if (r) { |
||||
bool b; |
||||
x[q] = cybozu::hextoi(&b, str, r); |
||||
if (!b) throw cybozu::Exception("fp:fromStr16:bad char") << cybozu::exception::makeString(str, strLen); |
||||
} |
||||
for (size_t i = requireSize; i < xn; i++) x[i] = 0; |
||||
} |
||||
|
||||
/*
|
||||
@param base [inout] |
||||
*/ |
||||
inline const char *verifyStr(bool *isMinus, int *base, const std::string& str) |
||||
{ |
||||
const char *p = str.c_str(); |
||||
if (*p == '-') { |
||||
*isMinus = true; |
||||
p++; |
||||
} else { |
||||
*isMinus = false; |
||||
} |
||||
if (p[0] == '0') { |
||||
if (p[1] == 'x') { |
||||
if (*base != 0 && *base != 16) { |
||||
throw cybozu::Exception("fp:verifyStr:bad base") << *base << str; |
||||
} |
||||
*base = 16; |
||||
p += 2; |
||||
} else if (p[1] == 'b') { |
||||
if (*base != 0 && *base != 2) { |
||||
throw cybozu::Exception("fp:verifyStr:bad base") << *base << str; |
||||
} |
||||
*base = 2; |
||||
p += 2; |
||||
} |
||||
} |
||||
if (*base == 0) *base = 10; |
||||
if (*p == '\0') throw cybozu::Exception("fp:verifyStr:str is empty"); |
||||
return p; |
||||
} |
||||
|
||||
template<class S> |
||||
size_t getRoundNum(size_t x) |
||||
{ |
||||
const size_t size = sizeof(S) * 8; |
||||
return (x + size - 1) / size; |
||||
} |
||||
|
||||
/*
|
||||
compare x[0, n) with y[0, n) |
||||
*/ |
||||
template<class S> |
||||
int compareArray(const S* x, const S* y, size_t n) |
||||
{ |
||||
for (size_t i = 0; i < n; i++) { |
||||
const S a = x[n - 1 - i]; |
||||
const S b = y[n - 1 - i]; |
||||
if (a > b) return 1; |
||||
if (a < b) return -1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
get random value less than in[] |
||||
n = (bitLen + sizeof(S) * 8) / (sizeof(S) * 8) |
||||
input in[0..n) |
||||
output out[n..n) |
||||
0 <= out < in |
||||
*/ |
||||
template<class RG, class S> |
||||
inline void getRandVal(S *out, RG& rg, const S *in, size_t bitLen) |
||||
{ |
||||
const size_t unitBitSize = sizeof(S) * 8; |
||||
const size_t n = getRoundNum<S>(bitLen); |
||||
const size_t rem = bitLen & (unitBitSize - 1); |
||||
for (;;) { |
||||
rg.read(out, n); |
||||
if (rem > 0) out[n - 1] &= (S(1) << rem) - 1; |
||||
if (compareArray(out, in, n) < 0) return; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
z[] = (x[] << shift) | y |
||||
@param z [out] z[0..n) |
||||
@param x [in] x[0..n) |
||||
@param n [in] length of x, z |
||||
@param shift [in] 0 <= shift < (sizeof(S) * 8) |
||||
@param y [in] |
||||
@return (x[] << shift)[n] |
||||
*/ |
||||
template<class S> |
||||
S shiftLeftOr(S* z, const S* x, size_t n, size_t shift, S y = 0) |
||||
{ |
||||
if (n == 0) { |
||||
throw cybozu::Exception("fp:shiftLeftOr:bad n"); |
||||
} |
||||
if (shift == 0) { |
||||
for (size_t i = n - 1; i > 0; i--) { |
||||
z[i] = x[i]; |
||||
} |
||||
z[0] = x[0] | y; |
||||
return 0; |
||||
} |
||||
const size_t unitSize = sizeof(S) * 8; |
||||
if (shift >= unitSize) { |
||||
throw cybozu::Exception("fp:shiftLeftOr:large shift") << shift; |
||||
} |
||||
const size_t rev = unitSize - shift; |
||||
S ret = x[n - 1] >> rev; |
||||
for (size_t i = n - 1; i > 0; i--) { |
||||
z[i] = (x[i] << shift) | (x[i - 1] >> rev); |
||||
} |
||||
z[0] = (x[0] << shift) | y; |
||||
return ret; |
||||
} |
||||
template<class S> |
||||
void shiftRight(S* z, const S* x, size_t n, size_t shift) |
||||
{ |
||||
if (n == 0) return; |
||||
if (shift == 0) { |
||||
for (size_t i = 0; i < n; i++) { |
||||
z[i] = x[i]; |
||||
} |
||||
return; |
||||
} |
||||
const size_t unitSize = sizeof(S) * 8; |
||||
if (shift >= unitSize) { |
||||
throw cybozu::Exception("fp:shiftRight:large shift") << shift; |
||||
} |
||||
const size_t rev = unitSize - shift; |
||||
S prev = x[0]; |
||||
for (size_t i = 0; i < n - 1; i++) { |
||||
S t = x[i + 1]; |
||||
z[i] = (prev >> shift) | (t << rev); |
||||
prev = t; |
||||
} |
||||
z[n - 1] = prev >> shift; |
||||
} |
||||
|
||||
template<class Vec, class T> |
||||
size_t splitBitVec(Vec& v, const cybozu::BitVectorT<T>& bv, size_t width) |
||||
{ |
||||
if (width > sizeof(typename Vec::value_type) * 8) { |
||||
throw cybozu::Exception("fp:splitBitVec:bad width") << width; |
||||
} |
||||
const size_t q = bv.size() / width; |
||||
const size_t r = bv.size() % width; |
||||
for (size_t i = 0; i < q; i++) { |
||||
v.push_back(bv.extract(i * width, width)); |
||||
} |
||||
if (r > 0) { |
||||
v.push_back(bv.extract(q * width, r)); |
||||
} |
||||
return r ? r : width; |
||||
} |
||||
|
||||
template<class Vec, class T> |
||||
void concatBitVec(cybozu::BitVectorT<T>& bv, const Vec& v, size_t width, size_t lastWidth) |
||||
{ |
||||
if (width > sizeof(typename Vec::value_type) * 8) { |
||||
throw cybozu::Exception("fp:splitBitVec:bad width") << width; |
||||
} |
||||
bv.clear(); |
||||
for (size_t i = 0; i < v.size() - 1; i++) { |
||||
bv.append(v[i], width); |
||||
} |
||||
bv.append(v[v.size() - 1], lastWidth); |
||||
} |
||||
|
||||
} // mcl::fp
|
||||
|
||||
} // fp
|
@ -0,0 +1,378 @@ |
||||
#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 <vector> |
||||
#include <assert.h> |
||||
#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 |
||||
#include <gmpxx.h> |
||||
#include <stdint.h> |
||||
#ifdef _MSC_VER |
||||
#pragma warning(pop) |
||||
#endif |
||||
#ifdef _MSC_VER |
||||
#if _MSC_VER == 1900 |
||||
#ifdef _DEBUG |
||||
#pragma comment(lib, "14/mpird.lib") |
||||
#pragma comment(lib, "14/mpirxxd.lib") |
||||
#else |
||||
#pragma comment(lib, "14/mpir.lib") |
||||
#pragma comment(lib, "14/mpirxx.lib") |
||||
#endif |
||||
#elif _MSC_VER == 1800 |
||||
#ifdef _DEBUG |
||||
#pragma comment(lib, "12/mpird.lib") |
||||
#pragma comment(lib, "12/mpirxxd.lib") |
||||
#else |
||||
#pragma comment(lib, "12/mpir.lib") |
||||
#pragma comment(lib, "12/mpirxx.lib") |
||||
#endif |
||||
#else |
||||
#ifdef _DEBUG |
||||
#pragma comment(lib, "mpird.lib") |
||||
#pragma comment(lib, "mpirxxd.lib") |
||||
#else |
||||
#pragma comment(lib, "mpir.lib") |
||||
#pragma comment(lib, "mpirxx.lib") |
||||
#endif |
||||
#endif |
||||
#endif |
||||
#include <mcl/operator.hpp> |
||||
|
||||
namespace mcl { |
||||
|
||||
struct Gmp { |
||||
typedef mpz_class ImplType; |
||||
#if CYBOZU_OS_BIT == 64 |
||||
typedef uint64_t BlockType; |
||||
#else |
||||
typedef uint32_t BlockType; |
||||
#endif |
||||
// z = [buf[n-1]:..:buf[1]:buf[0]]
|
||||
// eg. buf[] = {0x12345678, 0xaabbccdd}; => z = 0xaabbccdd12345678;
|
||||
template<class T> |
||||
static void setRaw(mpz_class& z, const T *buf, size_t n) |
||||
{ |
||||
mpz_import(z.get_mpz_t(), n, -1, sizeof(*buf), 0, 0, buf); |
||||
} |
||||
/*
|
||||
return positive written size |
||||
return 0 if failure |
||||
*/ |
||||
template<class T> |
||||
static size_t getRaw(T *buf, size_t maxSize, const mpz_class& x) |
||||
{ |
||||
const size_t totalSize = sizeof(T) * maxSize; |
||||
if (getBitLen(x) > totalSize * 8) return 0; |
||||
memset(buf, 0, sizeof(*buf) * maxSize); |
||||
size_t size; |
||||
mpz_export(buf, &size, -1, sizeof(T), 0, 0, x.get_mpz_t()); |
||||
// if x == 0, then size = 0 for gmp, size = 1 for mpir
|
||||
return size == 0 ? 1 : size; |
||||
} |
||||
static inline void set(mpz_class& z, uint64_t x) |
||||
{ |
||||
setRaw(z, &x, 1); |
||||
} |
||||
static inline bool fromStr(mpz_class& z, const std::string& str, int base = 0) |
||||
{ |
||||
return z.set_str(str, base) == 0; |
||||
} |
||||
static inline void toStr(std::string& str, const mpz_class& z, int base = 10) |
||||
{ |
||||
str = z.get_str(base); |
||||
} |
||||
static inline void add(mpz_class& z, const mpz_class& x, const mpz_class& y) |
||||
{ |
||||
mpz_add(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t()); |
||||
} |
||||
static 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); |
||||
} |
||||
static inline void sub(mpz_class& z, const mpz_class& x, const mpz_class& y) |
||||
{ |
||||
mpz_sub(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t()); |
||||
} |
||||
static 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); |
||||
} |
||||
static inline void mul(mpz_class& z, const mpz_class& x, const mpz_class& y) |
||||
{ |
||||
mpz_mul(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t()); |
||||
} |
||||
static inline void square(mpz_class& z, const mpz_class& x) |
||||
{ |
||||
mpz_mul(z.get_mpz_t(), x.get_mpz_t(), x.get_mpz_t()); |
||||
} |
||||
static 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); |
||||
} |
||||
static inline void divmod(mpz_class& q, mpz_class& r, const mpz_class& x, const mpz_class& y) |
||||
{ |
||||
mpz_divmod(q.get_mpz_t(), r.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t()); |
||||
} |
||||
static inline void div(mpz_class& q, const mpz_class& x, const mpz_class& y) |
||||
{ |
||||
mpz_div(q.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t()); |
||||
} |
||||
static 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); |
||||
} |
||||
static inline void mod(mpz_class& r, const mpz_class& x, const mpz_class& m) |
||||
{ |
||||
mpz_mod(r.get_mpz_t(), x.get_mpz_t(), m.get_mpz_t()); |
||||
} |
||||
static 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); |
||||
} |
||||
static inline void clear(mpz_class& z) |
||||
{ |
||||
mpz_set_ui(z.get_mpz_t(), 0); |
||||
} |
||||
static inline bool isZero(const mpz_class& z) |
||||
{ |
||||
return mpz_sgn(z.get_mpz_t()) == 0; |
||||
} |
||||
static inline bool isNegative(const mpz_class& z) |
||||
{ |
||||
return mpz_sgn(z.get_mpz_t()) < 0; |
||||
} |
||||
static inline void neg(mpz_class& z, const mpz_class& x) |
||||
{ |
||||
mpz_neg(z.get_mpz_t(), x.get_mpz_t()); |
||||
} |
||||
static inline int compare(const mpz_class& x, const mpz_class & y) |
||||
{ |
||||
return mpz_cmp(x.get_mpz_t(), y.get_mpz_t()); |
||||
} |
||||
static inline int compare(const mpz_class& x, int y) |
||||
{ |
||||
return mpz_cmp_si(x.get_mpz_t(), y); |
||||
} |
||||
template<class T> |
||||
static inline 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> |
||||
static inline 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> |
||||
static inline void mulMod(mpz_class& z, const mpz_class& x, const T& y, const mpz_class& m) |
||||
{ |
||||
mul(z, x, y); |
||||
mod(z, z, m); |
||||
} |
||||
static inline void squareMod(mpz_class& z, const mpz_class& x, const mpz_class& m) |
||||
{ |
||||
square(z, x); |
||||
mod(z, z, m); |
||||
} |
||||
// z = x^y (y >= 0)
|
||||
static inline void pow(mpz_class& z, const mpz_class& x, unsigned int y) |
||||
{ |
||||
mpz_pow_ui(z.get_mpz_t(), x.get_mpz_t(), y); |
||||
} |
||||
// z = x^y mod m (y >=0)
|
||||
static inline void powMod(mpz_class& z, const mpz_class& x, const mpz_class& y, const mpz_class& m) |
||||
{ |
||||
mpz_powm(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t(), m.get_mpz_t()); |
||||
} |
||||
// z = 1/x mod m
|
||||
static inline void invMod(mpz_class& z, const mpz_class& x, const mpz_class& m) |
||||
{ |
||||
mpz_invert(z.get_mpz_t(), x.get_mpz_t(), m.get_mpz_t()); |
||||
} |
||||
// z = lcm(x, y)
|
||||
static inline void lcm(mpz_class& z, const mpz_class& x, const mpz_class& y) |
||||
{ |
||||
mpz_lcm(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t()); |
||||
} |
||||
static 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)
|
||||
static inline void gcd(mpz_class& z, const mpz_class& x, const mpz_class& y) |
||||
{ |
||||
mpz_gcd(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t()); |
||||
} |
||||
static 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 |
||||
*/ |
||||
static inline int legendre(const mpz_class& a, const mpz_class& p) |
||||
{ |
||||
return mpz_legendre(a.get_mpz_t(), p.get_mpz_t()); |
||||
} |
||||
static inline bool isPrime(const mpz_class& x) |
||||
{ |
||||
return mpz_probab_prime_p(x.get_mpz_t(), 25) != 0; |
||||
} |
||||
static inline size_t getBitLen(const mpz_class& x) |
||||
{ |
||||
return mpz_sizeinbase(x.get_mpz_t(), 2); |
||||
} |
||||
static inline BlockType getBlock(const mpz_class& x, size_t i) |
||||
{ |
||||
return x.get_mpz_t()->_mp_d[i]; |
||||
} |
||||
static inline const BlockType *getBlock(const mpz_class& x) |
||||
{ |
||||
return reinterpret_cast<const BlockType*>(x.get_mpz_t()->_mp_d); |
||||
} |
||||
static inline size_t getBlockSize(const mpz_class& x) |
||||
{ |
||||
assert(x.get_mpz_t()->_mp_size >= 0); |
||||
return x.get_mpz_t()->_mp_size; |
||||
} |
||||
template<class RG> |
||||
static inline void getRand(mpz_class& z, size_t bitLen, RG& rg) |
||||
{ |
||||
assert(bitLen > 1); |
||||
const size_t rem = bitLen & 31; |
||||
const size_t n = (bitLen + 31) / 32; |
||||
std::vector<uint32_t> buf(n); |
||||
rg.read(buf.data(), n); |
||||
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; |
||||
Gmp::setRaw(z, &buf[0], n); |
||||
} |
||||
template<class RG> |
||||
static void getRandPrime(mpz_class& z, size_t bitLen, RG& rg, bool setSecondBit = false, bool mustBe3mod4 = false) |
||||
{ |
||||
assert(bitLen > 2); |
||||
do { |
||||
getRand(z, bitLen, rg); |
||||
if (setSecondBit) { |
||||
z |= mpz_class(1) << (bitLen - 2); |
||||
} |
||||
if (mustBe3mod4) { |
||||
z |= 3; |
||||
} |
||||
} while (!(isPrime(z))); |
||||
} |
||||
}; |
||||
|
||||
/*
|
||||
Tonelli-Shanks |
||||
*/ |
||||
class SquareRoot { |
||||
bool isPrime; |
||||
mpz_class p; |
||||
mpz_class g; |
||||
int r; |
||||
mpz_class q; // p - 1 = 2^r q
|
||||
mpz_class s; // s = g^q
|
||||
public: |
||||
SquareRoot() : isPrime(false) {} |
||||
void set(const mpz_class& p) |
||||
{ |
||||
if (p <= 2) throw cybozu::Exception("SquareRoot:bad p") << p; |
||||
isPrime = Gmp::isPrime(p); |
||||
if (!isPrime) return; // don't throw until get() is called
|
||||
this->p = p; |
||||
// g is quadratic nonresidue
|
||||
g = 2; |
||||
while (Gmp::legendre(g, p) > 0) { |
||||
g++; |
||||
} |
||||
// 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); |
||||
} |
||||
/*
|
||||
solve x^2 = a mod p |
||||
*/ |
||||
bool get(mpz_class& x, const mpz_class& a) const |
||||
{ |
||||
if (!isPrime) throw cybozu::Exception("SquareRoot:get:not prime") << p; |
||||
if (Gmp::legendre(a, p) < 0) return false; |
||||
if (r == 1) { |
||||
Gmp::powMod(x, a, (p + 1) / 4, p); |
||||
return true; |
||||
} |
||||
mpz_class c = s, d; |
||||
int e = r; |
||||
Gmp::powMod(d, a, q, p); |
||||
Gmp::powMod(x, a, (q + 1) / 2, p); // destroy a if &x == &a
|
||||
while (d != 1) { |
||||
int i = 1; |
||||
mpz_class dd = (d * d) % p; |
||||
while (dd != 1) { |
||||
dd = (dd * dd) % p; |
||||
i++; |
||||
} |
||||
mpz_class b = 1; |
||||
b <<= e - i - 1; |
||||
Gmp::powMod(b, c, b, p); |
||||
x = (x * b) % p; |
||||
c = (b * b) % p; |
||||
d = (d * c) % p; |
||||
e = i; |
||||
} |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
namespace ope { |
||||
|
||||
template<> |
||||
struct Optimized<mpz_class> { |
||||
void init(const mpz_class&) {} |
||||
bool hasPowMod() const { return true; } |
||||
static void powMod(mpz_class& z, const mpz_class& x, const mpz_class& y, const mpz_class& m) |
||||
{ |
||||
mpz_powm(z.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t(), m.get_mpz_t()); |
||||
} |
||||
}; |
||||
|
||||
} // mcl::ope
|
||||
|
||||
} // mcl
|
@ -0,0 +1,463 @@ |
||||
#pragma once |
||||
/**
|
||||
@file |
||||
@brief Fp with montgomery(EXPERIMENTAL IMPLEMENTAION) |
||||
@author MITSUNARI Shigeo(@herumi) |
||||
@license modified new BSD license |
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
|
||||
@note this class should be merged to FpT |
||||
*/ |
||||
#include <sstream> |
||||
#include <vector> |
||||
#include <mcl/gmp_util.hpp> |
||||
#include <mcl/fp.hpp> |
||||
#include <mcl/fp_generator.hpp> |
||||
|
||||
namespace mcl { |
||||
|
||||
template<size_t N, class tag = fp_local::TagDefault> |
||||
class MontFpT : public ope::addsub<MontFpT<N, tag>, |
||||
ope::mulable<MontFpT<N, tag>, |
||||
ope::invertible<MontFpT<N, tag>, |
||||
ope::hasNegative<MontFpT<N, tag>, |
||||
ope::hasIO<MontFpT<N, tag> > > > > > { |
||||
|
||||
static mpz_class pOrg_; |
||||
static mcl::SquareRoot sq_; |
||||
static MontFpT p_; |
||||
static MontFpT one_; |
||||
static MontFpT R_; // (1 << (N * 64)) % p
|
||||
static MontFpT RR_; // (R * R) % p
|
||||
static MontFpT invTbl_[N * 64 * 2]; |
||||
static size_t modBitLen_; |
||||
public: |
||||
static FpGenerator fg_; |
||||
private: |
||||
uint64_t v_[N]; |
||||
void fromRawGmp(const mpz_class& x) |
||||
{ |
||||
if (Gmp::getRaw(v_, N, x) == 0) { |
||||
throw cybozu::Exception("MontFpT:fromRawGmp") << x; |
||||
} |
||||
} |
||||
template<class S> |
||||
void setMaskMod(std::vector<S>& buf) |
||||
{ |
||||
assert(buf.size() * sizeof(S) * 8 <= modBitLen_); |
||||
assert(!buf.empty()); |
||||
fp::maskBuffer(&buf[0], buf.size(), modBitLen_); |
||||
memcpy(v_, &buf[0], buf.size() * sizeof(S)); |
||||
if (compare(*this, p_) >= 0) { |
||||
subNc(v_, v_, p_.v_); |
||||
} |
||||
assert(compare(*this, p_) < 0); |
||||
} |
||||
static void initInvTbl(MontFpT *invTbl) |
||||
{ |
||||
MontFpT t(2); |
||||
const int n = N * 64 * 2; |
||||
for (int i = 0; i < n; i++) { |
||||
invTbl[n - 1 - i] = t; |
||||
t += t; |
||||
} |
||||
} |
||||
typedef void (*void3op)(MontFpT&, const MontFpT&, const MontFpT&); |
||||
typedef bool (*bool3op)(MontFpT&, const MontFpT&, const MontFpT&); |
||||
typedef void (*void2op)(MontFpT&, const MontFpT&); |
||||
typedef int (*int2op)(MontFpT&, const MontFpT&); |
||||
public: |
||||
static const size_t BlockSize = N; |
||||
typedef uint64_t BlockType; |
||||
MontFpT() {} |
||||
MontFpT(int x) { operator=(x); } |
||||
MontFpT(uint64_t x) { operator=(x); } |
||||
explicit MontFpT(const std::string& str, int base = 0) |
||||
{ |
||||
fromStr(str, base); |
||||
} |
||||
MontFpT& operator=(int x) |
||||
{ |
||||
if (x == 0) { |
||||
clear(); |
||||
} else { |
||||
v_[0] = abs(x); |
||||
for (size_t i = 1; i < N; i++) v_[i] = 0; |
||||
mul(*this, *this, RR_); |
||||
if (x < 0) { |
||||
neg(*this, *this); |
||||
} |
||||
} |
||||
return *this; |
||||
} |
||||
MontFpT& operator=(uint64_t x) |
||||
{ |
||||
v_[0] = x; |
||||
for (size_t i = 1; i < N; i++) v_[i] = 0; |
||||
mul(*this, *this, RR_); |
||||
return *this; |
||||
} |
||||
void fromStr(const std::string& str, int base = 0) |
||||
{ |
||||
bool isMinus; |
||||
const char *p = fp::verifyStr(&isMinus, &base, str); |
||||
|
||||
if (base == 16) { |
||||
MontFpT t; |
||||
mcl::fp::fromStr16(t.v_, N, p, str.size() - (p - str.c_str())); |
||||
if (compare(t, p_) >= 0) throw cybozu::Exception("fp:MontFpT:str is too large") << str; |
||||
mul(*this, t, RR_); |
||||
} else { |
||||
mpz_class t; |
||||
if (!Gmp::fromStr(t, p, base)) { |
||||
throw cybozu::Exception("fp:MontFpT:fromStr") << str; |
||||
} |
||||
toMont(*this, t); |
||||
} |
||||
if (isMinus) { |
||||
neg(*this, *this); |
||||
} |
||||
} |
||||
void put() const |
||||
{ |
||||
for (int i = N - 1; i >= 0; i--) { |
||||
printf("%016llx ", v_[i]); |
||||
} |
||||
printf("\n"); |
||||
} |
||||
void set(const std::string& str, int base = 0) { fromStr(str, base); } |
||||
void toStr(std::string& str, int base = 10, bool withPrefix = false) const |
||||
{ |
||||
if (isZero()) { |
||||
str = "0"; |
||||
return; |
||||
} |
||||
if (base == 16 || base == 2) { |
||||
MontFpT t; |
||||
mul(t, *this, one_); |
||||
if (base == 16) { |
||||
mcl::fp::toStr16(str, t.v_, N, withPrefix); |
||||
} else { |
||||
mcl::fp::toStr2(str, t.v_, N, withPrefix); |
||||
} |
||||
return; |
||||
} |
||||
if (base != 10) throw cybozu::Exception("fp:MontFpT:toStr:bad base") << base; |
||||
// QQQ : remove conversion to gmp
|
||||
mpz_class t; |
||||
fromMont(t, *this); |
||||
Gmp::toStr(str, t, base); |
||||
} |
||||
std::string toStr(int base = 10, bool withPrefix = false) const |
||||
{ |
||||
std::string str; |
||||
toStr(str, base, withPrefix); |
||||
return str; |
||||
} |
||||
void clear() |
||||
{ |
||||
for (size_t i = 0; i < N; i++) v_[i] = 0; |
||||
} |
||||
template<class RG> |
||||
void setRand(RG& rg) |
||||
{ |
||||
fp::getRandVal(v_, rg, p_.v_, modBitLen_); |
||||
} |
||||
template<class S> |
||||
void setRaw(const S *inBuf, size_t n) |
||||
{ |
||||
n = std::min(n, fp::getRoundNum<S>(modBitLen_)); |
||||
if (n == 0) { |
||||
clear(); |
||||
return; |
||||
} |
||||
std::vector<S> buf(inBuf, inBuf + n); |
||||
setMaskMod(buf); |
||||
} |
||||
static inline void setModulo(const std::string& pstr, int base = 0) |
||||
{ |
||||
bool isMinus; |
||||
const char *p = fp::verifyStr(&isMinus, &base, pstr); |
||||
if (isMinus) throw cybozu::Exception("MontFp:setModulo:mstr is not pinus") << pstr; |
||||
if (!Gmp::fromStr(pOrg_, p, base)) { |
||||
throw cybozu::Exception("fp:MontFpT:setModulo") << pstr << base; |
||||
} |
||||
modBitLen_ = Gmp::getBitLen(pOrg_); |
||||
if (fp::getRoundNum<uint64_t>(modBitLen_) > N) { |
||||
throw cybozu::Exception("MontFp:setModulo:bad prime length") << pstr; |
||||
} |
||||
p_.fromRawGmp(pOrg_); |
||||
sq_.set(pOrg_); |
||||
|
||||
mpz_class t = 1; |
||||
one_.fromRawGmp(t); |
||||
t = (t << (N * 64)) % pOrg_; |
||||
R_.fromRawGmp(t); |
||||
t = (t * t) % pOrg_; |
||||
RR_.fromRawGmp(t); |
||||
fg_.init(p_.v_, N); |
||||
add = Xbyak::CastTo<void3op>(fg_.add_); |
||||
sub = Xbyak::CastTo<void3op>(fg_.sub_); |
||||
mul = Xbyak::CastTo<void3op>(fg_.mul_); |
||||
square = Xbyak::CastTo<void2op>(fg_.sqr_); |
||||
if (square == 0) square = squareC; |
||||
neg = Xbyak::CastTo<void2op>(fg_.neg_); |
||||
shr1 = Xbyak::CastTo<void2op>(fg_.shr1_); |
||||
addNc = Xbyak::CastTo<bool3op>(fg_.addNc_); |
||||
subNc = Xbyak::CastTo<bool3op>(fg_.subNc_); |
||||
preInv = Xbyak::CastTo<int2op>(fg_.preInv_); |
||||
initInvTbl(invTbl_); |
||||
} |
||||
static inline void getModulo(std::string& pstr) |
||||
{ |
||||
Gmp::toStr(pstr, pOrg_); |
||||
} |
||||
static inline bool isYodd(const MontFpT& y) |
||||
{ |
||||
#if 0 |
||||
return (y.v_[0] & 1) == 1; |
||||
#else |
||||
MontFpT t; // QQQ : is necessary?
|
||||
mul(t, y, one_); |
||||
return (t.v_[0] & 1) == 1; |
||||
#endif |
||||
} |
||||
static inline bool squareRoot(MontFpT& y, const MontFpT& x) |
||||
{ |
||||
mpz_class t; |
||||
fromMont(t, x); |
||||
if (!sq_.get(t, t)) return false; |
||||
toMont(y, t); |
||||
return true; |
||||
} |
||||
static inline void fromMont(mpz_class& z, const MontFpT& x) |
||||
{ |
||||
MontFpT t; |
||||
mul(t, x, one_); |
||||
Gmp::setRaw(z, t.v_, N); |
||||
} |
||||
static inline void toMont(MontFpT& z, const mpz_class& x) |
||||
{ |
||||
if (x >= pOrg_) throw cybozu::Exception("fp:MontFpT:toMont:large x") << x; |
||||
MontFpT t; |
||||
t.fromRawGmp(x); |
||||
mul(z, t, RR_); |
||||
} |
||||
static void3op add; |
||||
static void3op sub; |
||||
static void3op mul; |
||||
static void2op square; |
||||
static void2op neg; |
||||
static void2op shr1; |
||||
static bool3op addNc; |
||||
static bool3op subNc; |
||||
static int2op preInv; |
||||
static inline void squareC(MontFpT& z, const MontFpT& x) |
||||
{ |
||||
mul(z, x, x); |
||||
} |
||||
static inline int preInvC(MontFpT& r, const MontFpT& x) |
||||
{ |
||||
MontFpT u, v, s; |
||||
u = p_; |
||||
v = x; |
||||
r.clear(); |
||||
s.clear(); s.v_[0] = 1; // s is real 1
|
||||
int k = 0; |
||||
// u, v : Pack, r, s : mem
|
||||
bool rTop = false; |
||||
LP: |
||||
if (v.isZero()) goto EXIT; |
||||
if ((u.v_[0] & 1) == 0) { |
||||
goto U_EVEN; |
||||
} |
||||
if ((v.v_[0] & 1) == 0) { |
||||
goto V_EVEN; |
||||
} |
||||
if (compare(v, u) < 0) { |
||||
goto V_LT_U; |
||||
} |
||||
subNc(v, v, u); // sub_rr
|
||||
addNc(s, s, r); // add_mm
|
||||
V_EVEN: |
||||
shr1(v, v); // shr1_r
|
||||
rTop = addNc(r, r, r); // twice_m
|
||||
k++; |
||||
goto LP; |
||||
V_LT_U: |
||||
subNc(u, u, v); // sub_rr
|
||||
rTop = addNc(r, r, s); // add_mm
|
||||
U_EVEN: |
||||
shr1(u, u); // shr1_r
|
||||
addNc(s, s, s); // twice_m
|
||||
k++; |
||||
goto LP; |
||||
EXIT:; |
||||
if (rTop) subNc(r, r, p_); |
||||
if (subNc(r, p_, r)) { |
||||
addNc(r, r, p_); |
||||
} |
||||
return k; |
||||
} |
||||
static inline void inv(MontFpT& z, const MontFpT& x) |
||||
{ |
||||
#if 1 |
||||
MontFpT r; |
||||
#if 1 |
||||
int k = preInv(r, x); |
||||
#else |
||||
MontFpT s; |
||||
int h = preInvC(s, x); |
||||
int k = preInv(r, x); |
||||
if (r != s || k != h) { |
||||
std::cout << std::hex; |
||||
PUT(x); |
||||
PUT(r); |
||||
PUT(s); |
||||
printf("k=%d, h=%d\n", k, h); |
||||
exit(1); |
||||
} |
||||
#endif |
||||
/*
|
||||
xr = 2^k |
||||
R = 2^(N * 64) |
||||
get r2^(-k)R^2 = r 2^(N * 64 * 2 - k) |
||||
*/ |
||||
mul(z, r, invTbl_[k]); |
||||
#else |
||||
mpz_class t; |
||||
fromMont(t, x); |
||||
Gmp::invMod(t, t, pOrg_); |
||||
toMont(z, t); |
||||
#endif |
||||
} |
||||
static inline void div(MontFpT& z, const MontFpT& x, const MontFpT& y) |
||||
{ |
||||
MontFpT ry; |
||||
inv(ry, y); |
||||
mul(z, x, ry); |
||||
} |
||||
#if 0 |
||||
static inline BlockType getBlock(const MontFpT& x, size_t i) |
||||
{ |
||||
return Gmp::getBlock(x.v, i); |
||||
} |
||||
static inline const BlockType *getBlock(const MontFpT& x) |
||||
{ |
||||
return Gmp::getBlock(x.v); |
||||
} |
||||
static inline size_t getBlockSize(const MontFpT& x) |
||||
{ |
||||
return Gmp::getBlockSize(x.v); |
||||
} |
||||
static inline void shr(MontFpT& z, const MontFpT& x, size_t n) |
||||
{ |
||||
z.v = x.v >> n; |
||||
} |
||||
#endif |
||||
/*
|
||||
append to bv(not clear bv) |
||||
*/ |
||||
void appendToBitVec(cybozu::BitVector& bv) const |
||||
{ |
||||
MontFpT t; |
||||
MontFpT::mul(t, *this, MontFpT::one_); |
||||
bv.append(t.v_, modBitLen_); |
||||
} |
||||
void fromBitVec(const cybozu::BitVector& bv) |
||||
{ |
||||
const size_t bitLen = bv.size(); |
||||
if (bitLen != modBitLen_) throw cybozu::Exception("MontFp:fromBitVec:bad size") << bitLen << modBitLen_; |
||||
const size_t blockN = cybozu::RoundupBit<BlockType>(bitLen); |
||||
const MontFpT* src; |
||||
MontFpT t; |
||||
if (blockN == N) { |
||||
src = (const MontFpT*)bv.getBlock(); |
||||
} else { |
||||
cybozu::CopyBit(t.v_, bv.getBlock(), bitLen); |
||||
for (size_t i = blockN; i < N; i++) t.v_[i] = 0; |
||||
src = &t; |
||||
} |
||||
mul(*this, *src, RR_); |
||||
if (compare(*this, p_) >= 0) { |
||||
throw cybozu::Exception("MontFpT:fromBitVec:large x") << *this << p_; |
||||
} |
||||
} |
||||
static inline size_t getBitVecSize() { return modBitLen_; } |
||||
static inline int compare(const MontFpT& x, const MontFpT& y) |
||||
{ |
||||
return fp::compareArray(x.v_, y.v_, N); |
||||
} |
||||
static inline bool isZero(const MontFpT& x) |
||||
{ |
||||
if (x.v_[0]) return false; |
||||
uint64_t r = 0; |
||||
for (size_t i = 1; i < N; i++) { |
||||
r |= x.v_[i]; |
||||
} |
||||
return r == 0; |
||||
} |
||||
bool isZero() const { return isZero(*this); } |
||||
template<class Z> |
||||
static void power(MontFpT& z, const MontFpT& x, const Z& y) |
||||
{ |
||||
power_impl::power(z, x, y); |
||||
} |
||||
const uint64_t* getInnerValue() const { return v_; } |
||||
bool operator==(const MontFpT& rhs) const { return compare(*this, rhs) == 0; } |
||||
bool operator!=(const MontFpT& rhs) const { return compare(*this, rhs) != 0; } |
||||
static inline size_t getModBitLen() { return modBitLen_; } |
||||
static inline uint64_t cvtInt(const MontFpT& x, bool *err = 0) |
||||
{ |
||||
MontFpT t; |
||||
mul(t, x, one_); |
||||
for (size_t i = 1; i < N; i++) { |
||||
if (t.v_[i]) { |
||||
if (err) { |
||||
*err = true; |
||||
return 0; |
||||
} else { |
||||
throw cybozu::Exception("MontFp:cvtInt:too large") << x; |
||||
} |
||||
} |
||||
} |
||||
if (err) *err = false; |
||||
return t.v_[0]; |
||||
} |
||||
uint64_t cvtInt(bool *err = 0) const { return cvtInt(*this, err); } |
||||
}; |
||||
|
||||
template<size_t N, class tag>mpz_class MontFpT<N, tag>::pOrg_; |
||||
template<size_t N, class tag>mcl::SquareRoot MontFpT<N, tag>::sq_; |
||||
template<size_t N, class tag>MontFpT<N, tag> MontFpT<N, tag>::p_; |
||||
template<size_t N, class tag>MontFpT<N, tag> MontFpT<N, tag>::one_; |
||||
template<size_t N, class tag>MontFpT<N, tag> MontFpT<N, tag>::R_; |
||||
template<size_t N, class tag>MontFpT<N, tag> MontFpT<N, tag>::RR_; |
||||
template<size_t N, class tag>MontFpT<N, tag> MontFpT<N, tag>::invTbl_[N * 64 * 2]; |
||||
template<size_t N, class tag>FpGenerator MontFpT<N, tag>::fg_; |
||||
template<size_t N, class tag>size_t MontFpT<N, tag>::modBitLen_; |
||||
|
||||
template<size_t N, class tag>typename MontFpT<N, tag>::void3op MontFpT<N, tag>::add; |
||||
template<size_t N, class tag>typename MontFpT<N, tag>::void3op MontFpT<N, tag>::sub; |
||||
template<size_t N, class tag>typename MontFpT<N, tag>::void3op MontFpT<N, tag>::mul; |
||||
template<size_t N, class tag>typename MontFpT<N, tag>::void2op MontFpT<N, tag>::square; |
||||
template<size_t N, class tag>typename MontFpT<N, tag>::void2op MontFpT<N, tag>::neg; |
||||
template<size_t N, class tag>typename MontFpT<N, tag>::void2op MontFpT<N, tag>::shr1; |
||||
template<size_t N, class tag>typename MontFpT<N, tag>::bool3op MontFpT<N, tag>::addNc; |
||||
template<size_t N, class tag>typename MontFpT<N, tag>::bool3op MontFpT<N, tag>::subNc; |
||||
template<size_t N, class tag>typename MontFpT<N, tag>::int2op MontFpT<N, tag>::preInv; |
||||
|
||||
} // mcl
|
||||
|
||||
namespace std { CYBOZU_NAMESPACE_TR1_BEGIN |
||||
template<class T> struct hash; |
||||
|
||||
template<size_t N, class tag> |
||||
struct hash<mcl::MontFpT<N, tag> > { |
||||
size_t operator()(const mcl::MontFpT<N, tag>& x, uint64_t v = 0) const |
||||
{ |
||||
return static_cast<size_t>(cybozu::hash64(x.getInnerValue(), N, v)); |
||||
} |
||||
}; |
||||
|
||||
CYBOZU_NAMESPACE_TR1_END } // std::tr1
|
@ -0,0 +1,118 @@ |
||||
#pragma once |
||||
/**
|
||||
@file |
||||
@brief operator |
||||
@author MITSUNARI Shigeo(@herumi) |
||||
@license modified new BSD license |
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
*/ |
||||
#include <ios> |
||||
#include <cybozu/exception.hpp> |
||||
|
||||
#ifdef _WIN32 |
||||
#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 ope { |
||||
|
||||
template<class T> |
||||
struct Empty {}; |
||||
|
||||
/*
|
||||
T must have compare |
||||
*/ |
||||
template<class T, class E = Empty<T> > |
||||
struct comparable : E { |
||||
friend MCL_FORCE_INLINE bool operator<(const T& x, const T& y) { return T::compare(x, y) < 0; } |
||||
friend MCL_FORCE_INLINE bool operator>=(const T& x, const T& y) { return !operator<(x, y); } |
||||
|
||||
friend MCL_FORCE_INLINE bool operator>(const T& x, const T& y) { return T::compare(x, y) > 0; } |
||||
friend MCL_FORCE_INLINE bool operator<=(const T& x, const T& y) { return !operator>(x, y); } |
||||
friend MCL_FORCE_INLINE bool operator==(const T& x, const T& y) { return T::compare(x, y) == 0; } |
||||
friend MCL_FORCE_INLINE bool operator!=(const T& x, const T& y) { return !operator==(x, y); } |
||||
}; |
||||
|
||||
/*
|
||||
T must have add, sub |
||||
*/ |
||||
template<class T, class E = Empty<T> > |
||||
struct addsub : 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; } |
||||
}; |
||||
|
||||
/*
|
||||
T must have mul |
||||
*/ |
||||
template<class T, class E = Empty<T> > |
||||
struct mulable : E { |
||||
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; } |
||||
}; |
||||
|
||||
/*
|
||||
T must have inv, mul |
||||
*/ |
||||
template<class T, class E = Empty<T> > |
||||
struct invertible : E { |
||||
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); } |
||||
friend MCL_FORCE_INLINE T operator/(const T& a, const T& b) { T c; T::inv(c, b); T::mul(c, c, a); return c; } |
||||
}; |
||||
|
||||
/*
|
||||
T must have neg |
||||
*/ |
||||
template<class T, class E = Empty<T> > |
||||
struct hasNegative : E { |
||||
MCL_FORCE_INLINE T operator-() const { T c; T::neg(c, static_cast<const T&>(*this)); return c; } |
||||
}; |
||||
|
||||
template<class T, class E = Empty<T> > |
||||
struct hasIO : E { |
||||
friend inline std::ostream& operator<<(std::ostream& os, const T& self) |
||||
{ |
||||
const std::ios_base::fmtflags f = os.flags(); |
||||
if (f & std::ios_base::oct) throw cybozu::Exception("fpT:operator<<:oct is not supported"); |
||||
const int base = (f & std::ios_base::hex) ? 16 : 10; |
||||
const bool showBase = (f & std::ios_base::showbase) != 0; |
||||
std::string str; |
||||
self.toStr(str, base, showBase); |
||||
return os << str; |
||||
} |
||||
friend inline std::istream& operator>>(std::istream& is, T& self) |
||||
{ |
||||
const std::ios_base::fmtflags f = is.flags(); |
||||
if (f & std::ios_base::oct) throw cybozu::Exception("fpT:operator>>:oct is not supported"); |
||||
const int base = (f & std::ios_base::hex) ? 16 : 0; |
||||
std::string str; |
||||
is >> str; |
||||
self.fromStr(str, base); |
||||
return is; |
||||
} |
||||
}; |
||||
|
||||
template<class T> |
||||
struct Optimized { |
||||
bool hasMulMod() const { return false; } |
||||
void init(const T&) {} |
||||
static void mulMod(T&, const T&, const T&) {} |
||||
static void mulMod(T&, const T&, unsigned int) {} |
||||
bool hasPowMod() const { return false; } |
||||
static void powMod(T&, const T&, const T&, const T&) {} |
||||
}; |
||||
|
||||
} } // mcl::ope
|
||||
|
||||
#ifdef _WIN32 |
||||
// #pragma warning(pop)
|
||||
#endif |
@ -0,0 +1,181 @@ |
||||
#pragma once |
||||
/**
|
||||
@file |
||||
@brief power |
||||
@author MITSUNARI Shigeo(@herumi) |
||||
@license modified new BSD license |
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
*/ |
||||
#include <assert.h> |
||||
#include <cybozu/bit_operation.hpp> |
||||
#include <mcl/tagmultigr.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 |
||||
#include <gmpxx.h> |
||||
#ifdef _MSC_VER |
||||
#pragma warning(pop) |
||||
#endif |
||||
|
||||
namespace mcl { |
||||
|
||||
namespace power_impl { |
||||
|
||||
template<class F> |
||||
struct TagInt { |
||||
typedef typename F::BlockType BlockType; |
||||
static size_t getBlockSize(const F& x) |
||||
{ |
||||
return F::getBlockSize(x); |
||||
} |
||||
static BlockType getBlock(const F& x, size_t i) |
||||
{ |
||||
return F::getBlock(x, i); |
||||
} |
||||
static const BlockType* getBlock(const F& x) |
||||
{ |
||||
return F::getBlock(x); |
||||
} |
||||
static size_t getBitLen(const F& x) |
||||
{ |
||||
return F::getBitLen(x); |
||||
} |
||||
static void shr(F& x, size_t n) |
||||
{ |
||||
F::shr(x, x, n); |
||||
} |
||||
}; |
||||
|
||||
template<> |
||||
struct TagInt<int> { |
||||
typedef int BlockType; |
||||
static int getBlockSize(int) |
||||
{ |
||||
return 1; |
||||
} |
||||
static BlockType getBlock(int x, size_t i) |
||||
{ |
||||
assert(i == 0); |
||||
cybozu::disable_warning_unused_variable(i); |
||||
return x; |
||||
} |
||||
static const BlockType* getBlock(const int& x) |
||||
{ |
||||
return &x; |
||||
} |
||||
static size_t getBitLen(int x) |
||||
{ |
||||
return x == 0 ? 1 : cybozu::bsr(x) + 1; |
||||
} |
||||
static void shr(int& x, size_t n) |
||||
{ |
||||
x >>= n; |
||||
} |
||||
}; |
||||
|
||||
template<> |
||||
struct TagInt<size_t> { |
||||
typedef size_t BlockType; |
||||
static size_t getBlockSize(size_t) |
||||
{ |
||||
return 1; |
||||
} |
||||
static BlockType getBlock(size_t x, size_t i) |
||||
{ |
||||
assert(i == 0); |
||||
cybozu::disable_warning_unused_variable(i); |
||||
return x; |
||||
} |
||||
static const BlockType* getBlock(const size_t& x) |
||||
{ |
||||
return &x; |
||||
} |
||||
static size_t getBitLen(size_t x) |
||||
{ |
||||
return x == 0 ? 1 : cybozu::bsr<size_t>(x) + 1; |
||||
} |
||||
static void shr(size_t& x, size_t n) |
||||
{ |
||||
x >>= n; |
||||
} |
||||
}; |
||||
|
||||
template<> |
||||
struct TagInt<mpz_class> { |
||||
typedef mp_limb_t BlockType; |
||||
static size_t getBlockSize(const mpz_class& x) |
||||
{ |
||||
return x.get_mpz_t()->_mp_size; |
||||
} |
||||
static BlockType getBlock(const mpz_class& x, size_t i) |
||||
{ |
||||
return x.get_mpz_t()->_mp_d[i]; |
||||
} |
||||
static const BlockType* getBlock(const mpz_class& x) |
||||
{ |
||||
return x.get_mpz_t()->_mp_d; |
||||
} |
||||
static size_t getBitLen(const mpz_class& x) |
||||
{ |
||||
return mpz_sizeinbase(x.get_mpz_t(), 2); |
||||
} |
||||
static void shr(mpz_class& x, size_t n) |
||||
{ |
||||
x >>= n; |
||||
} |
||||
}; |
||||
|
||||
template<class G, class BlockType> |
||||
void powerArray(G& z, const G& x, const BlockType *y, size_t n) |
||||
{ |
||||
typedef TagMultiGr<G> TagG; |
||||
G out; |
||||
TagG::init(out); |
||||
G t(x); |
||||
for (size_t i = 0; i < n; i++) { |
||||
BlockType v = y[i]; |
||||
int m = (int)sizeof(BlockType) * 8; |
||||
if (i == n - 1) { |
||||
// avoid unused multiplication
|
||||
while (m > 0 && (v & (BlockType(1) << (m - 1))) == 0) { |
||||
m--; |
||||
} |
||||
} |
||||
for (int j = 0; j < m; j++) { |
||||
if (v & (BlockType(1) << j)) { |
||||
TagG::mul(out, out, t); |
||||
} |
||||
TagG::square(t, t); |
||||
} |
||||
} |
||||
z = out; |
||||
} |
||||
|
||||
template<class G, class F> |
||||
void power(G& z, const G& x, const F& _y) |
||||
{ |
||||
typedef TagMultiGr<G> TagG; |
||||
typedef power_impl::TagInt<F> TagI; |
||||
if (_y == 0) { |
||||
TagG::init(z); |
||||
return; |
||||
} |
||||
if (_y == 1) { |
||||
z = x; |
||||
return; |
||||
} |
||||
bool isNegative = _y < 0; |
||||
const F& y = isNegative ? -_y : _y; |
||||
powerArray(z, x, TagI::getBlock(y), TagI::getBlockSize(y)); |
||||
if (isNegative) { |
||||
TagG::inv(z, z); |
||||
} |
||||
} |
||||
|
||||
} } // mcl::power_impl
|
@ -0,0 +1,39 @@ |
||||
#pragma once |
||||
/**
|
||||
@file |
||||
@brief TagMultiGr |
||||
@author MITSUNARI Shigeo(@herumi) |
||||
@license modified new BSD license |
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
*/ |
||||
#include <assert.h> |
||||
|
||||
namespace mcl { |
||||
|
||||
// default tag is for multiplicative group
|
||||
template<class G> |
||||
struct TagMultiGr { |
||||
static void square(G& z, const G& x) |
||||
{ |
||||
G::mul(z, x, x); |
||||
} |
||||
static void mul(G& z, const G& x, const G& y) |
||||
{ |
||||
G::mul(z, x, y); |
||||
} |
||||
static void inv(G& z, const G& x) |
||||
{ |
||||
G::inv(z, x); |
||||
} |
||||
static void div(G& z, const G& x, const G& y) |
||||
{ |
||||
G::div(z, x, y); |
||||
} |
||||
static void init(G& x) |
||||
{ |
||||
x = 1; |
||||
} |
||||
}; |
||||
|
||||
} // mcl
|
||||
|
@ -0,0 +1,25 @@ |
||||
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
# Visual Studio Express 2012 for Windows Desktop |
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fp_test", "test\proj\fp_test\fp_test.vcxproj", "{51266DE6-B57B-4AE3-B85C-282F170E1728}" |
||||
EndProject |
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ec_test", "test\proj\ec_test\ec_test.vcxproj", "{46B6E88E-739A-406B-9F68-BC46C5950FA3}" |
||||
EndProject |
||||
Global |
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
Debug|x64 = Debug|x64 |
||||
Release|x64 = Release|x64 |
||||
EndGlobalSection |
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
{51266DE6-B57B-4AE3-B85C-282F170E1728}.Debug|x64.ActiveCfg = Debug|x64 |
||||
{51266DE6-B57B-4AE3-B85C-282F170E1728}.Debug|x64.Build.0 = Debug|x64 |
||||
{51266DE6-B57B-4AE3-B85C-282F170E1728}.Release|x64.ActiveCfg = Release|x64 |
||||
{51266DE6-B57B-4AE3-B85C-282F170E1728}.Release|x64.Build.0 = Release|x64 |
||||
{46B6E88E-739A-406B-9F68-BC46C5950FA3}.Debug|x64.ActiveCfg = Debug|x64 |
||||
{46B6E88E-739A-406B-9F68-BC46C5950FA3}.Debug|x64.Build.0 = Debug|x64 |
||||
{46B6E88E-739A-406B-9F68-BC46C5950FA3}.Release|x64.ActiveCfg = Release|x64 |
||||
{46B6E88E-739A-406B-9F68-BC46C5950FA3}.Release|x64.Build.0 = Release|x64 |
||||
EndGlobalSection |
||||
GlobalSection(SolutionProperties) = preSolution |
||||
HideSolutionNode = FALSE |
||||
EndGlobalSection |
||||
EndGlobal |
@ -0,0 +1,12 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ImportGroup Label="PropertySheets" /> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup /> |
||||
<ItemDefinitionGroup> |
||||
<ClCompile> |
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> |
||||
</ClCompile> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup /> |
||||
</Project> |
@ -0,0 +1,23 @@ |
||||
include ../common.mk |
||||
|
||||
TARGET=$(TEST_FILE)
|
||||
LIBS=
|
||||
|
||||
SRC=$(wildcard *.cpp)
|
||||
|
||||
all: $(TARGET) |
||||
|
||||
test: $(TARGET) |
||||
@$(SAMPLE_TEST)
|
||||
|
||||
$(OBJDIR): |
||||
@$(MKDIR) $(OBJDIR)
|
||||
|
||||
clean: |
||||
$(CLEAN)
|
||||
|
||||
$(LIBS): |
||||
$(MAKE) -C ../src
|
||||
|
||||
-include $(DEPEND_FILE) |
||||
|
@ -0,0 +1,69 @@ |
||||
/*
|
||||
sample of Elliptic Curve Diffie-Hellman key sharing |
||||
*/ |
||||
#include <iostream> |
||||
#include <fstream> |
||||
#include <cybozu/random_generator.hpp> |
||||
#include <mcl/fp.hpp> |
||||
#include <mcl/gmp_util.hpp> |
||||
#include <mcl/ecparam.hpp> |
||||
#include <mcl/ec.hpp> |
||||
#include <mcl/fp.hpp> |
||||
typedef mcl::FpT<> Fp; |
||||
|
||||
struct ZnTag; |
||||
|
||||
typedef mcl::EcT<Fp> Ec; |
||||
typedef mcl::FpT<ZnTag> Zn; |
||||
|
||||
int main() |
||||
{ |
||||
cybozu::RandomGenerator rg; |
||||
/*
|
||||
system setup with a parameter secp192k1 recommended by SECG |
||||
Ec is an elliptic curve over Fp |
||||
the cyclic group of <P> is isomorphic to Zn |
||||
*/ |
||||
const mcl::EcParam& para = mcl::ecparam::secp192k1; |
||||
Zn::setModulo(para.n); |
||||
Fp::setModulo(para.p); |
||||
Ec::setParam(para.a, para.b); |
||||
const Ec P(Fp(para.gx), Fp(para.gy)); |
||||
|
||||
/*
|
||||
Alice setups a private key a and public key aP |
||||
*/ |
||||
Zn a; |
||||
Ec aP; |
||||
|
||||
a.setRand(rg); |
||||
Ec::power(aP, P, a); // aP = a * P;
|
||||
|
||||
std::cout << "aP=" << aP << std::endl; |
||||
|
||||
/*
|
||||
Bob setups a private key b and public key bP |
||||
*/ |
||||
Zn b; |
||||
Ec bP; |
||||
|
||||
b.setRand(rg); |
||||
Ec::power(bP, P, b); // bP = b * P;
|
||||
|
||||
std::cout << "bP=" << bP << std::endl; |
||||
|
||||
Ec abP, baP; |
||||
|
||||
// Alice uses bP(B's public key) and a(A's priavte key)
|
||||
Ec::power(abP, bP, a); // abP = a * (bP)
|
||||
|
||||
// Bob uses aP(A's public key) and b(B's private key)
|
||||
Ec::power(baP, aP, b); // baP = b * (aP)
|
||||
|
||||
if (abP == baP) { |
||||
std::cout << "key sharing succeed:" << abP << std::endl; |
||||
} else { |
||||
std::cout << "ERR(not here)" << std::endl; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,29 @@ |
||||
#include <mcl/fp.hpp> |
||||
#include <mcl/gmp_util.hpp> |
||||
#include <mcl/ecparam.hpp> |
||||
#include <cybozu/random_generator.hpp> |
||||
#include <map> |
||||
#include <mcl/fp.hpp> |
||||
typedef mcl::FpT<> Fp; |
||||
|
||||
typedef std::map<std::string, int> Map; |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
cybozu::RandomGenerator rg; |
||||
const char *p = mcl::ecparam::secp192k1.p; |
||||
if (argc == 2) { |
||||
p = argv[1]; |
||||
} |
||||
Fp::setModulo(p); |
||||
Fp x; |
||||
printf("p=%s\n", p); |
||||
Map m; |
||||
for (int i = 0; i < 10000; i++) { |
||||
x.setRand(rg); |
||||
m[x.toStr(16)]++; |
||||
} |
||||
for (Map::const_iterator i = m.begin(), ie = m.end(); i != ie; ++i) { |
||||
printf("%s %d\n", i->first.c_str(), i->second); |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
VER=-3.5
|
||||
LLC=llc$(VER)
|
||||
OPT=opt$(VER)
|
||||
DIS=llvm-dis$(VER)
|
||||
ASM=llvm-as$(VER)
|
||||
OPT_LLC= $(OPT) -O3 -o - | $(LLC) -O3 -o -
|
||||
|
||||
SRC = once.txt all.txt long.txt short.txt mul.txt
|
||||
TARGET=x64.s x86.s arm.s arm64.s
|
||||
AFLAGS=-mattr=bmi2
|
||||
all: $(TARGET) |
||||
|
||||
base64.ll: gen.py $(SRC) |
||||
python gen.py 64
|
||||
|
||||
base32.ll: gen.py $(SRC) |
||||
python gen.py 32
|
||||
|
||||
x64: base64.ll |
||||
$(LLC) base64.ll -o - -x86-asm-syntax=intel
|
||||
x86: base32.ll |
||||
$(LLC) base32.ll -o - -x86-asm-syntax=intel -march=x86
|
||||
arm64: base64.ll |
||||
$(LLC) base64.ll -o - -march=aarch64
|
||||
|
||||
arm: base32.ll |
||||
$(LLC) base32.ll -o - -march=arm
|
||||
|
||||
opt: base64.ll |
||||
cat base64.ll|$(OPT_LLC) -x86-asm-syntax=intel $(AFLAGS)
|
||||
|
||||
x64.s: base64.ll |
||||
cat base64.ll|$(OPT_LLC) $(AFLAGS) > x64.s
|
||||
x86.s: base32.ll |
||||
cat base32.ll|$(OPT_LLC) $(AFLAGS) -march=x86 > x86.s
|
||||
arm.s: base32.ll |
||||
cat base32.ll|$(OPT_LLC) -march=arm > arm.s
|
||||
arm64.s: base32.ll |
||||
cat base64.ll|$(OPT_LLC) -march=aarch64 > arm64.s
|
||||
clean: |
||||
rm -rf base*.ll *.s
|
||||
|
@ -0,0 +1,7 @@ |
||||
declare { i$(bit), i1 } @llvm.usub.with.overflow.i$(bit)(i$(bit) %x, i$(bit) %y) |
||||
|
||||
define i$(unit) @extract$(bit+unit)(i$(bit+unit) %x, i$(bit+unit) %shift) { |
||||
%t0 = lshr i$(bit+unit) %x, %shift |
||||
%t1 = trunc i$(bit+unit) %t0 to i$(unit) |
||||
ret i$(unit) %t1 |
||||
} |
@ -0,0 +1,187 @@ |
||||
import sys, re |
||||
|
||||
# @for <var>, <begin>, <end> |
||||
RE_FOR = re.compile(r'@for\s+(\w+)\s*,\s*([^ ]+)\s*,\s*([^ ]+)') |
||||
# $(<exp>) |
||||
RE_VAL = re.compile(r'\$\(([^)]+)\)') |
||||
# @define <var>=<exp> |
||||
RE_DEFINE = re.compile(r'@define\s+(\w+)\s*=(.*)') |
||||
# @if <exp> |
||||
RE_IF = re.compile(r'@if\s+(.*)') |
||||
# @elif <exp> |
||||
RE_ELIF = re.compile(r'@elif\s+(.*)') |
||||
|
||||
def evalStr(s, envG, envL={}): |
||||
def eval2str(x): |
||||
s = x.group(1) |
||||
v = eval(s, envG, envL) |
||||
return str(v) |
||||
s = RE_VAL.sub(eval2str, s) |
||||
return s |
||||
|
||||
def parseDefine(s, envG, envL): |
||||
""" |
||||
if s is @define statement, then update envL and return True |
||||
otherwise return False |
||||
""" |
||||
p = RE_DEFINE.match(s) |
||||
if not p: |
||||
return False |
||||
lhs = p.group(1).strip() |
||||
rhs = p.group(2).strip() |
||||
envL[lhs] = eval(rhs, envG, envL) |
||||
return True |
||||
|
||||
def parseFor(s, envG): |
||||
""" |
||||
@for i, 0, 3 |
||||
<exp> |
||||
@endif |
||||
|
||||
| |
||||
v |
||||
@define i = 0 |
||||
<exp> |
||||
exp |
||||
@define i = 1 |
||||
<exp> |
||||
@define i = 2 |
||||
<exp> |
||||
|
||||
""" |
||||
out = "" |
||||
inFor = False |
||||
envL = {} |
||||
for line in s.split('\n'): |
||||
stripped = line.strip() |
||||
# save @define for parseIf |
||||
parseDefine(stripped, envG, envL) |
||||
if inFor: |
||||
if line.strip() == '@endfor': |
||||
inFor = False |
||||
for i in xrange(b, e): |
||||
out += "@define %s = %d\n" % (v, i) |
||||
out += sub |
||||
else: |
||||
sub += line + '\n' |
||||
else: |
||||
p = RE_FOR.search(stripped) |
||||
if p: |
||||
v = p.group(1).strip() |
||||
b = eval(p.group(2), envG) |
||||
e = eval(p.group(3), envG) |
||||
sub = "" |
||||
inFor = True |
||||
else: |
||||
out += line + '\n' |
||||
return out |
||||
|
||||
def parseIf(s, envG): |
||||
out = "" |
||||
IF_INIT = 0 |
||||
IF_IF = 1 |
||||
IF_ELSE = 2 |
||||
ifState = IF_INIT |
||||
ifVar = False |
||||
# available variables in @(<expr>) |
||||
envL = {} |
||||
def evalIntLoc(s): |
||||
return eval(s, envG, envL) |
||||
for line in s.split('\n'): |
||||
stripped = line.strip() |
||||
# remove @define |
||||
if parseDefine(stripped, envG, envL): |
||||
continue |
||||
if ifState == IF_INIT: |
||||
p = RE_IF.match(stripped) |
||||
if p: |
||||
ifState = IF_IF |
||||
ifVar = evalIntLoc(p.group(1)) |
||||
continue |
||||
elif ifState == IF_IF: |
||||
if stripped == '@endif': |
||||
ifState = IF_INIT |
||||
continue |
||||
elif stripped == '@else': |
||||
ifState = IF_ELSE |
||||
ifVar = not ifVar |
||||
continue |
||||
p = RE_ELIF.match(stripped) |
||||
if p: |
||||
ifVar = evalIntLoc(p.group(1)) |
||||
continue |
||||
if not ifVar: |
||||
continue |
||||
elif ifState == IF_ELSE: |
||||
if stripped == '@endif': |
||||
ifState = IF_INIT |
||||
continue |
||||
if not ifVar: |
||||
continue |
||||
else: |
||||
raise Exception('bad state', ifState) |
||||
out += evalStr(line, envG, envL) + '\n' |
||||
return out |
||||
|
||||
def parse(s, unitL, bitL): |
||||
""" |
||||
eval "@(<expr>)" to integer |
||||
|
||||
@for <var>, <begin>, <end> |
||||
... |
||||
@endfor |
||||
|
||||
REMARK : @for is not nestable |
||||
|
||||
@define <var> = <exp> |
||||
REMARK : var is global |
||||
|
||||
@if <exp> |
||||
@elif <exp> |
||||
@endif |
||||
|
||||
REMARK : @if is not nestable |
||||
""" |
||||
# available variables in @(<expr>) |
||||
envG = { |
||||
'unit' : unitL, |
||||
'bit' : bitL, |
||||
'N' : bitL / unitL, |
||||
} |
||||
s = parseFor(s, envG) |
||||
s = parseIf(s, envG) |
||||
return s |
||||
|
||||
def gen(fo, inLame, unitL, bitLL): |
||||
fi = open(inLame, 'r') |
||||
s = fi.read() |
||||
fi.close() |
||||
for bitL in bitLL: |
||||
t = parse(s, unitL, bitL) |
||||
fo.write(t) |
||||
|
||||
def main(): |
||||
argv = sys.argv |
||||
args = len(argv) |
||||
unitL = 64 |
||||
if args == 2: |
||||
unitL = int(argv[1]) |
||||
if unitL not in [32, 64]: |
||||
print "bad unitL", unitL |
||||
exit(1) |
||||
|
||||
outLame = 'base%d.ll' % unitL |
||||
fo = open(outLame, 'w') |
||||
# gen(fo, 't.txt', unitL, [unitL * 4]) |
||||
# exit(1) |
||||
gen(fo, 'once.txt', unitL, [unitL * 2]) |
||||
|
||||
bitLL = range(unitL, 576 + 1, unitL) |
||||
gen(fo, 'all.txt', unitL, bitLL) |
||||
gen(fo, 'short.txt', unitL, bitLL) |
||||
gen(fo, 'long.txt', unitL, bitLL) |
||||
gen(fo, 'mul.txt', unitL, bitLL[1:]) |
||||
fo.close() |
||||
|
||||
if __name__ == "__main__": |
||||
main() |
@ -0,0 +1,54 @@ |
||||
define void @mcl_fp_add$(bit)L(i$(bit)* %pz, i$(bit)* %px, i$(bit)* %py, i$(bit)* %pp) { |
||||
%x = load i$(bit)* %px |
||||
%y = load i$(bit)* %py |
||||
%p = load i$(bit)* %pp |
||||
%x1 = zext i$(bit) %x to i$(bit+unit) |
||||
%y1 = zext i$(bit) %y to i$(bit+unit) |
||||
%p1 = zext i$(bit) %p to i$(bit+unit) |
||||
%t0 = add i$(bit+unit) %x1, %y1 ; x + y |
||||
%t1 = trunc i$(bit+unit) %t0 to i$(bit) |
||||
store i$(bit) %t1, i$(bit)* %pz |
||||
%vc = sub i$(bit+unit) %t0, %p1 |
||||
%c = lshr i$(bit+unit) %vc, $(bit+unit-1) |
||||
%c1 = trunc i$(bit+unit) %c to i1 |
||||
br i1 %c1, label %carry, label %nocarry |
||||
nocarry: |
||||
%v = trunc i$(bit+unit) %vc to i$(bit) |
||||
store i$(bit) %v, i$(bit)* %pz |
||||
ret void |
||||
carry: |
||||
ret void |
||||
} |
||||
|
||||
define internal { i$(bit), i$(unit) } @local_sbb$(bit)(i$(bit) %x, i$(bit) %y) { |
||||
%x1 = zext i$(bit) %x to i$(bit+unit) |
||||
%y1 = zext i$(bit) %y to i$(bit+unit) |
||||
%v1 = sub i$(bit+unit) %x1, %y1 |
||||
%v = trunc i$(bit+unit) %v1 to i$(bit) |
||||
%c = lshr i$(bit+unit) %v1, $(bit) |
||||
%c1 = trunc i$(bit+unit) %c to i$(unit) |
||||
%r1 = insertvalue { i$(bit), i$(unit) } undef, i$(bit) %v, 0 |
||||
%r2 = insertvalue { i$(bit), i$(unit) } %r1, i$(unit) %c1, 1 |
||||
ret { i$(bit), i$(unit) } %r2 |
||||
} |
||||
|
||||
define void @mcl_fp_sub$(bit)L(i$(bit)* %pz, i$(bit)* %px, i$(bit)* %py, i$(bit)* %pp) { |
||||
%x = load i$(bit)* %px |
||||
%y = load i$(bit)* %py |
||||
%x1 = zext i$(bit) %x to i$(bit+unit) |
||||
%y1 = zext i$(bit) %y to i$(bit+unit) |
||||
%vc = sub i$(bit+unit) %x1, %y1 |
||||
%v = trunc i$(bit+unit) %vc to i$(bit) |
||||
%c = lshr i$(bit+unit) %vc, $(bit+unit-1) |
||||
%c1 = trunc i$(bit+unit) %c to i1 |
||||
store i$(bit) %v, i$(bit)* %pz |
||||
br i1 %c1, label %carry, label %nocarry |
||||
nocarry: |
||||
ret void |
||||
carry: |
||||
%p = load i$(bit)* %pp |
||||
%t = add i$(bit) %v, %p ; x - y + p |
||||
store i$(bit) %t, i$(bit)* %pz |
||||
ret void |
||||
} |
||||
|
@ -0,0 +1,81 @@ |
||||
@define bu = bit + unit |
||||
define private i$(bu) @mul$(bit)x$(unit)(i$(bit) %x, i$(unit) %y) |
||||
@if N > 4 |
||||
noinline |
||||
@endif |
||||
{ |
||||
@for i, 0, N |
||||
%x$(i) = call i$(unit) @extract$(bit)(i$(bit) %x, i$(bit) $(unit*i)) |
||||
%x$(i)y = call i$(unit*2) @mul$(unit)x$(unit)(i$(unit) %x$(i), i$(unit) %y) |
||||
%x$(i)y0 = zext i$(unit*2) %x$(i)y to i$(bu) |
||||
@endfor |
||||
@for i, 1, N |
||||
%x$(i)y1 = shl i$(bu) %x$(i)y0, $(unit*i) |
||||
@endfor |
||||
%t0 = add i$(bu) %x0y0, %x1y1 |
||||
@for i, 1, N-1 |
||||
%t$(i) = add i$(bu) %t$(i-1), %x$(i+1)y1 |
||||
@endfor |
||||
ret i$(bu) %t$(N-2) |
||||
} |
||||
define void @mcl_fp_mul$(bit)pre(i$(unit)* %pz, i$(bit)* %px, i$(bit)* %py) { |
||||
%x = load i$(bit)* %px |
||||
%y = load i$(bit)* %py |
||||
@for i, 0, N |
||||
%y$(i) = call i$(unit) @extract$(bit)(i$(bit) %y, i$(bit) $(unit*i)) |
||||
@endfor |
||||
%sum0 = call i$(bu) @mul$(bit)x$(unit)(i$(bit) %x, i$(unit) %y0) |
||||
%t0 = trunc i$(bu) %sum0 to i$(unit) |
||||
store i$(unit) %t0, i$(unit)* %pz |
||||
@for i, 1, N |
||||
|
||||
%s$(i-1) = lshr i$(bu) %sum$(i-1), $(unit) |
||||
%xy$(i) = call i$(bu) @mul$(bit)x$(unit)(i$(bit) %x, i$(unit) %y$(i)) |
||||
%sum$(i) = add i$(bu) %s$(i-1), %xy$(i) |
||||
%z$(i) = getelementptr i$(unit)* %pz, i32 $(i) |
||||
@if i < N - 1 |
||||
%ts$(i) = trunc i$(bu) %sum$(i) to i$(unit) |
||||
store i$(unit) %ts$(i), i$(unit)* %z$(i) |
||||
@endif |
||||
@endfor |
||||
%p = bitcast i$(unit)* %z$(N-1) to i$(bu)* |
||||
store i$(bu) %sum$(N-1), i$(bu)* %p |
||||
ret void |
||||
} |
||||
|
||||
@define bu = bit + unit |
||||
@define bu2 = bit + unit * 2 |
||||
define void @mcl_fp_mont$(bit)(i$(bit)* %pz, i$(bit)* %px, i$(unit)* %py, i$(bit)* %pp, i$(unit) %r) { |
||||
%p = load i$(bit)* %pp |
||||
%x = load i$(bit)* %px |
||||
|
||||
@for i, 0, N |
||||
%py$(i) = getelementptr i$(unit)* %py, i$(unit) $(i) |
||||
%y$(i) = load i$(unit)* %py$(i) |
||||
%xy$(i) = call i$(bu) @mul$(bit)x$(unit)(i$(bit) %x, i$(unit) %y$(i)) |
||||
@if i == 0 |
||||
%a0 = zext i$(bu) %xy0 to i$(bu2) |
||||
|
||||
%at$(i) = trunc i$(bu) %xy$(i) to i$(unit) |
||||
@else |
||||
%xye$(i) = zext i$(bu) %xy$(i) to i$(bu2) |
||||
%a$(i) = add i$(bu2) %s$(i-1), %xye$(i) |
||||
%at$(i) = trunc i$(bu2) %a$(i) to i$(unit) |
||||
@endif |
||||
%q$(i) = mul i$(unit) %at$(i), %r |
||||
%pq$(i) = call i$(bu) @mul$(bit)x$(unit)(i$(bit) %p, i$(unit) %q$(i)) |
||||
%pqe$(i) = zext i$(bu) %pq$(i) to i$(bu2) |
||||
%t$(i) = add i$(bu2) %a$(i), %pqe$(i) |
||||
%s$(i) = lshr i$(bu2) %t$(i), $(unit) |
||||
@endfor |
||||
%v = trunc i$(bu2) %s$(N-1) to i$(bu) |
||||
%pe = zext i$(bit) %p to i$(bu) |
||||
%vc = sub i$(bu) %v, %pe |
||||
%c = lshr i$(bu) %vc, $(bit) |
||||
%c1 = trunc i$(bu) %c to i1 |
||||
%z = select i1 %c1, i$(bu) %v, i$(bu) %vc |
||||
%zt = trunc i$(bu) %z to i$(bit) |
||||
store i$(bit) %zt, i$(bit)* %pz |
||||
ret void |
||||
} |
||||
|
@ -0,0 +1,74 @@ |
||||
|
||||
define i$(unit*2) @mul$(unit)x$(unit)(i$(unit) %x, i$(unit) %y) { |
||||
%x0 = zext i$(unit) %x to i$(unit*2) |
||||
%y0 = zext i$(unit) %y to i$(unit*2) |
||||
%z = mul i$(unit*2) %x0, %y0 |
||||
ret i$(unit*2) %z |
||||
} |
||||
|
||||
; NIST_P192 |
||||
; 0xfffffffffffffffffffffffffffffffeffffffffffffffff |
||||
; |
||||
; 0 1 2 |
||||
; ffffffffffffffff fffffffffffffffe ffffffffffffffff |
||||
; |
||||
; p = (1 << 192) - (1 << 64) - 1 |
||||
; (1 << 192) % p = (1 << 64) + 1 |
||||
; |
||||
; L : 192bit |
||||
; Hi: 64bit |
||||
; x = [H:L] = [H2:H1:H0:L] |
||||
; mod p |
||||
; x = L + H + (H << 64) |
||||
; = L + H + [H1:H0:0] + H2 + (H2 << 64) |
||||
;[e:t] = L + H + [H1:H0:H2] + [H2:0] ; 2bit(e) over |
||||
; = t + e + (e << 64) |
||||
|
||||
define internal i64 @extract192to64(i192 %x, i192 %shift) { |
||||
%t0 = lshr i192 %x, %shift |
||||
%t1 = trunc i192 %t0 to i64 |
||||
ret i64 %t1 |
||||
} |
||||
|
||||
define internal void @modNIST_P192(i192* %out, i192* %px) { |
||||
%L192 = load i192* %px |
||||
%L = zext i192 %L192 to i256 |
||||
|
||||
%pH = getelementptr i192* %px, i32 1 |
||||
%H192 = load i192* %pH |
||||
%H = zext i192 %H192 to i256 |
||||
|
||||
%H10_ = shl i192 %H192, 64 |
||||
%H10 = zext i192 %H10_ to i256 |
||||
|
||||
%H2_ = call i64 @extract192to64(i192 %H192, i192 128) |
||||
%H2 = zext i64 %H2_ to i256 |
||||
%H102 = or i256 %H10, %H2 |
||||
|
||||
%H2s = shl i256 %H2, 64 |
||||
|
||||
%t0 = add i256 %L, %H |
||||
%t1 = add i256 %t0, %H102 |
||||
%t2 = add i256 %t1, %H2s |
||||
|
||||
%e = lshr i256 %t2, 192 |
||||
%t3 = trunc i256 %t2 to i192 |
||||
%e1 = trunc i256 %e to i192 |
||||
|
||||
|
||||
%t4 = add i192 %t3, %e1 |
||||
%e2 = shl i192 %e1, 64 |
||||
%t5 = add i192 %t4, %e2 |
||||
|
||||
store i192 %t5, i192* %out |
||||
|
||||
ret void |
||||
} |
||||
|
||||
define void @mcl_fp_mul_NIST_P192(i192* %pz, i192* %px, i192* %py) { |
||||
%buf = alloca i192, i32 2 |
||||
%p = bitcast i192* %buf to i$(unit)* |
||||
call void @mcl_fp_mul192pre(i$(unit)* %p, i192* %px, i192* %py) |
||||
call void @modNIST_P192(i192* %pz, i192* %buf) |
||||
ret void |
||||
} |
@ -0,0 +1,46 @@ |
||||
define void @mcl_fp_add$(bit)S(i$(bit)* %pz, i$(bit)* %px, i$(bit)* %py, i$(bit)* %pp) { |
||||
entry: |
||||
%x = load i$(bit)* %px |
||||
%y = load i$(bit)* %py |
||||
%p = load i$(bit)* %pp |
||||
%x1 = zext i$(bit) %x to i$(bit+unit) |
||||
%y1 = zext i$(bit) %y to i$(bit+unit) |
||||
%p1 = zext i$(bit) %p to i$(bit+unit) |
||||
%t0 = add i$(bit+unit) %x1, %y1 ; x + y |
||||
%t1 = sub i$(bit+unit) %t0, %p1 ; x + y - p |
||||
%t2 = lshr i$(bit+unit) %t1, $(bit) |
||||
%t3 = trunc i$(bit+unit) %t2 to i1 |
||||
%t4 = select i1 %t3, i$(bit+unit) %t0, i$(bit+unit) %t1 |
||||
%t5 = trunc i$(bit+unit) %t4 to i$(bit) |
||||
store i$(bit) %t5, i$(bit)* %pz |
||||
ret void |
||||
} |
||||
|
||||
define internal { i$(bit), i$(unit) } @mcl_local_sbb$(bit)(i$(bit) %x, i$(bit) %y) { |
||||
%x1 = zext i$(bit) %x to i$(bit+unit) |
||||
%y1 = zext i$(bit) %y to i$(bit+unit) |
||||
%v1 = sub i$(bit+unit) %x1, %y1 |
||||
%v = trunc i$(bit+unit) %v1 to i$(bit) |
||||
%c = lshr i$(bit+unit) %v1, $(bit) |
||||
%c1 = trunc i$(bit+unit) %c to i$(unit) |
||||
%r1 = insertvalue { i$(bit), i$(unit) } undef, i$(bit) %v, 0 |
||||
%r2 = insertvalue { i$(bit), i$(unit) } %r1, i$(unit) %c1, 1 |
||||
ret { i$(bit), i$(unit) } %r2 |
||||
} |
||||
|
||||
define void @mcl_fp_sub$(bit)S(i$(bit)* %pz, i$(bit)* %px, i$(bit)* %py, i$(bit)* %pp) { |
||||
%x = load i$(bit)* %px |
||||
%y = load i$(bit)* %py |
||||
%x1 = zext i$(bit) %x to i$(bit+unit) |
||||
%y1 = zext i$(bit) %y to i$(bit+unit) |
||||
%vc = sub i$(bit+unit) %x1, %y1 |
||||
%v = trunc i$(bit+unit) %vc to i$(bit) |
||||
%c = lshr i$(bit+unit) %vc, $(bit+unit-1) |
||||
%c1 = trunc i$(bit+unit) %c to i1 |
||||
%p = load i$(bit)* %pp |
||||
%a = select i1 %c1, i$(bit) %p, i$(bit) 0 |
||||
%v1 = add i$(bit) %v, %a |
||||
store i$(bit) %v1, i$(bit)* %pz |
||||
ret void |
||||
} |
||||
|
@ -0,0 +1,42 @@ |
||||
include ../common.mk |
||||
|
||||
ifeq ($(USE_MONT_FP),1) |
||||
CFLAGS += -DUSE_MONT_FP
|
||||
endif |
||||
|
||||
ifeq ($(USE_LLVM),1) |
||||
CFLAGS += -DMIE_USE_LLVM
|
||||
ASM_SRC=../src/$(CPU).s
|
||||
ASM_OBJ=$(ASM_SRC:.s=.o)
|
||||
SRC+=$(ASM_SRC)
|
||||
LDFLAGS+=$(ASM_OBJ)
|
||||
endif |
||||
|
||||
TARGET=$(TEST_FILE)
|
||||
LIBS=
|
||||
|
||||
SRC=fp_test.cpp ec_test.cpp fp_util_test.cpp
|
||||
ifeq ($(CPU),x64) |
||||
SRC+=fp_generator_test.cpp mont_fp_test.cpp
|
||||
endif |
||||
|
||||
all: $(TARGET) |
||||
|
||||
test: $(TARGET) $(ASM_OBJ) |
||||
@$(UNIT_TEST)
|
||||
|
||||
$(OBJDIR): |
||||
@$(MKDIR) $(OBJDIR)
|
||||
|
||||
clean: |
||||
$(CLEAN)
|
||||
|
||||
$(LIBS): |
||||
$(MAKE) -C ../src
|
||||
|
||||
-include $(DEPEND_FILE) |
||||
|
||||
ifeq ($(USE_LLVM),1) |
||||
$(ASM_OBJ): $(ASM_SRC) |
||||
$(CXX) $< -o $@ -c
|
||||
endif |
@ -0,0 +1,392 @@ |
||||
#include <map> |
||||
#define MCL_USE_LLVM |
||||
#include <mcl/fp_base.hpp> |
||||
#include <cybozu/test.hpp> |
||||
#include <cybozu/benchmark.hpp> |
||||
#include <cybozu/xorshift.hpp> |
||||
#include <cybozu/bit_operation.hpp> |
||||
#include <mcl/fp_util.hpp> |
||||
#include <mcl/fp.hpp> |
||||
|
||||
#include <mcl/fp_generator.hpp> |
||||
#if (CYBOZU_HOST == CYBOZU_HOST_INTEL) && (CYBOZU_OS_BIT == 64) |
||||
#define USE_XBYAK |
||||
static mcl::FpGenerator fg; |
||||
#endif |
||||
#define PUT(x) std::cout << #x "=" << (x) << std::endl |
||||
|
||||
const size_t MAX_N = 32; |
||||
typedef mcl::fp::Unit Unit; |
||||
|
||||
size_t getUnitN(size_t bitLen) |
||||
{ |
||||
return (bitLen + sizeof(Unit) * 8 - 1) / (sizeof(Unit) * 8); |
||||
} |
||||
|
||||
void setMpz(mpz_class& mx, const Unit *x, size_t n) |
||||
{ |
||||
mcl::Gmp::setRaw(mx, x, n); |
||||
} |
||||
void getMpz(Unit *x, size_t n, const mpz_class& mx) |
||||
{ |
||||
mcl::fp::local::toArray(x, n, mx.get_mpz_t()); |
||||
} |
||||
|
||||
struct Montgomery { |
||||
mpz_class p_; |
||||
mpz_class R_; // (1 << (n_ * 64)) % p
|
||||
mpz_class RR_; // (R * R) % p
|
||||
Unit r_; // p * r = -1 mod M = 1 << 64
|
||||
size_t n_; |
||||
Montgomery() {} |
||||
explicit Montgomery(const mpz_class& p) |
||||
{ |
||||
p_ = p; |
||||
r_ = mcl::montgomery::getCoff(mcl::Gmp::getBlock(p, 0)); |
||||
n_ = mcl::Gmp::getBlockSize(p); |
||||
R_ = 1; |
||||
R_ = (R_ << (n_ * 64)) % p_; |
||||
RR_ = (R_ * R_) % p_; |
||||
} |
||||
|
||||
void toMont(mpz_class& x) const { mul(x, x, RR_); } |
||||
void fromMont(mpz_class& x) const { mul(x, x, 1); } |
||||
|
||||
void mont(Unit *z, const Unit *x, const Unit *y) const |
||||
{ |
||||
mpz_class mx, my; |
||||
setMpz(mx, x, n_); |
||||
setMpz(my, y, n_); |
||||
mul(mx, mx, my); |
||||
getMpz(z, n_, mx); |
||||
} |
||||
void mul(mpz_class& z, const mpz_class& x, const mpz_class& y) const |
||||
{ |
||||
#if 1 |
||||
const size_t ySize = mcl::Gmp::getBlockSize(y); |
||||
mpz_class c = y == 0 ? mpz_class(0) : x * mcl::Gmp::getBlock(y, 0); |
||||
Unit q = c == 0 ? 0 : mcl::Gmp::getBlock(c, 0) * r_; |
||||
c += p_ * q; |
||||
c >>= sizeof(Unit) * 8; |
||||
for (size_t i = 1; i < n_; i++) { |
||||
if (i < ySize) { |
||||
c += x * mcl::Gmp::getBlock(y, i); |
||||
} |
||||
Unit q = c == 0 ? 0 : mcl::Gmp::getBlock(c, 0) * r_; |
||||
c += p_ * q; |
||||
c >>= sizeof(Unit) * 8; |
||||
} |
||||
if (c >= p_) { |
||||
c -= p_; |
||||
} |
||||
z = c; |
||||
#else |
||||
z = x * y; |
||||
const size_t zSize = mcl::Gmp::getBlockSize(z); |
||||
for (size_t i = 0; i < n_; i++) { |
||||
if (i < zSize) { |
||||
Unit q = mcl::Gmp::getBlock(z, 0) * r_; |
||||
z += p_ * (mp_limb_t)q; |
||||
} |
||||
z >>= sizeof(Unit) * 8; |
||||
} |
||||
if (z >= p_) { |
||||
z -= p_; |
||||
} |
||||
#endif |
||||
} |
||||
}; |
||||
|
||||
void put(const char *msg, const Unit *x, size_t n) |
||||
{ |
||||
printf("%s ", msg); |
||||
for (size_t i = 0; i < n; i++) printf("%016llx ", (long long)x[n - 1 - i]); |
||||
printf("\n"); |
||||
} |
||||
void verifyEqual(const Unit *x, const Unit *y, size_t n, const char *file, int line) |
||||
{ |
||||
bool ok = mcl::fp::local::isEqualArray(x, y, n); |
||||
CYBOZU_TEST_ASSERT(ok); |
||||
if (ok) return; |
||||
printf("%s:%d\n", file, line); |
||||
put("L", x, n); |
||||
put("R", y, n); |
||||
exit(1); |
||||
} |
||||
#define VERIFY_EQUAL(x, y, n) verifyEqual(x, y, n, __FILE__, __LINE__) |
||||
|
||||
void addC(Unit *z, const Unit *x, const Unit *y, const Unit *p, size_t n) |
||||
{ |
||||
mpz_class mx, my, mp; |
||||
setMpz(mx, x, n); |
||||
setMpz(my, y, n); |
||||
setMpz(mp, p, n); |
||||
mx += my; |
||||
if (mx >= mp) mx -= mp; |
||||
getMpz(z, n, mx); |
||||
} |
||||
void subC(Unit *z, const Unit *x, const Unit *y, const Unit *p, size_t n) |
||||
{ |
||||
mpz_class mx, my, mp; |
||||
setMpz(mx, x, n); |
||||
setMpz(my, y, n); |
||||
setMpz(mp, p, n); |
||||
mx -= my; |
||||
if (mx < 0) mx += mp; |
||||
getMpz(z, n, mx); |
||||
} |
||||
static inline void set_zero(mpz_t& z, Unit *p, size_t n) |
||||
{ |
||||
z->_mp_alloc = (int)n; |
||||
z->_mp_size = 0; |
||||
z->_mp_d = (mp_limb_t*)p; |
||||
} |
||||
static inline void set_mpz_t(mpz_t& z, const Unit* p, int n) |
||||
{ |
||||
z->_mp_alloc = n; |
||||
int i = n; |
||||
while (i > 0 && p[i - 1] == 0) { |
||||
i--; |
||||
} |
||||
z->_mp_size = i; |
||||
z->_mp_d = (mp_limb_t*)p; |
||||
} |
||||
|
||||
// z[2n] <- x[n] * y[n]
|
||||
void mulPreC(Unit *z, const Unit *x, const Unit *y, size_t n) |
||||
{ |
||||
#if 1 |
||||
mpz_t mx, my, mz; |
||||
set_zero(mz, z, n * 2); |
||||
set_mpz_t(mx, x, n); |
||||
set_mpz_t(my, y, n); |
||||
mpz_mul(mz, mx, my); |
||||
mcl::fp::local::toArray(z, n * 2, mz); |
||||
#else |
||||
mpz_class mx, my; |
||||
setMpz(mx, x, n); |
||||
setMpz(my, y, n); |
||||
mx *= my; |
||||
getMpz(z, n * 2, mx); |
||||
#endif |
||||
} |
||||
|
||||
void modC(Unit *y, const Unit *x, const Unit *p, size_t n) |
||||
{ |
||||
mpz_t mx, my, mp; |
||||
set_mpz_t(mx, x, n * 2); |
||||
set_mpz_t(my, y, n); |
||||
set_mpz_t(mp, p, n); |
||||
mpz_mod(my, mx, mp); |
||||
mcl::fp::local::clearArray(y, my->_mp_size, n); |
||||
} |
||||
|
||||
void mul(Unit *z, const Unit *x, const Unit *y, const Unit *p, size_t n) |
||||
{ |
||||
Unit ret[MAX_N * 2]; |
||||
mpz_t mx, my, mz, mp; |
||||
set_zero(mz, ret, MAX_N * 2); |
||||
set_mpz_t(mx, x, n); |
||||
set_mpz_t(my, y, n); |
||||
set_mpz_t(mp, p, n); |
||||
mpz_mul(mz, mx, my); |
||||
mpz_mod(mz, mz, mp); |
||||
mcl::fp::local::toArray(z, n, mz); |
||||
} |
||||
|
||||
typedef mcl::fp::void3op void3op; |
||||
typedef mcl::fp::void4op void4op; |
||||
typedef mcl::fp::void4Iop void4Iop; |
||||
|
||||
const struct FuncOp { |
||||
size_t bitLen; |
||||
void4op addS; |
||||
void4op addL; |
||||
void4op subS; |
||||
void4op subL; |
||||
void3op mulPre; |
||||
void4Iop mont; |
||||
} gFuncOpTbl[] = { |
||||
{ 128, mcl_fp_add128S, mcl_fp_add128L, mcl_fp_sub128S, mcl_fp_sub128L, mcl_fp_mul128pre, mcl_fp_mont128 }, |
||||
{ 192, mcl_fp_add192S, mcl_fp_add192L, mcl_fp_sub192S, mcl_fp_sub192L, mcl_fp_mul192pre, mcl_fp_mont192 }, |
||||
{ 256, mcl_fp_add256S, mcl_fp_add256L, mcl_fp_sub256S, mcl_fp_sub256L, mcl_fp_mul256pre, mcl_fp_mont256 }, |
||||
{ 320, mcl_fp_add320S, mcl_fp_add320L, mcl_fp_sub320S, mcl_fp_sub320L, mcl_fp_mul320pre, mcl_fp_mont320 }, |
||||
{ 384, mcl_fp_add384S, mcl_fp_add384L, mcl_fp_sub384S, mcl_fp_sub384L, mcl_fp_mul384pre, mcl_fp_mont384 }, |
||||
{ 448, mcl_fp_add448S, mcl_fp_add448L, mcl_fp_sub448S, mcl_fp_sub448L, mcl_fp_mul448pre, mcl_fp_mont448 }, |
||||
{ 512, mcl_fp_add512S, mcl_fp_add512L, mcl_fp_sub512S, mcl_fp_sub512L, mcl_fp_mul512pre, mcl_fp_mont512 }, |
||||
#if CYBOZU_OS_BIT == 32 |
||||
{ 160, mcl_fp_add160S, mcl_fp_add160L, mcl_fp_sub160S, mcl_fp_sub160L, mcl_fp_mul160pre, mcl_fp_mont160 }, |
||||
{ 224, mcl_fp_add224S, mcl_fp_add224L, mcl_fp_sub224S, mcl_fp_sub224L, mcl_fp_mul224pre, mcl_fp_mont224 }, |
||||
{ 288, mcl_fp_add288S, mcl_fp_add288L, mcl_fp_sub288S, mcl_fp_sub288L, mcl_fp_mul288pre, mcl_fp_mont288 }, |
||||
{ 352, mcl_fp_add352S, mcl_fp_add352L, mcl_fp_sub352S, mcl_fp_sub352L, mcl_fp_mul352pre, mcl_fp_mont352 }, |
||||
{ 416, mcl_fp_add416S, mcl_fp_add416L, mcl_fp_sub416S, mcl_fp_sub416L, mcl_fp_mul416pre, mcl_fp_mont416 }, |
||||
{ 480, mcl_fp_add480S, mcl_fp_add480L, mcl_fp_sub480S, mcl_fp_sub480L, mcl_fp_mul480pre, mcl_fp_mont480 }, |
||||
{ 544, mcl_fp_add544S, mcl_fp_add544L, mcl_fp_sub544S, mcl_fp_sub544L, mcl_fp_mul544pre, mcl_fp_mont544 }, |
||||
#else |
||||
{ 576, mcl_fp_add576S, mcl_fp_add576L, mcl_fp_sub576S, mcl_fp_sub576L, mcl_fp_mul576pre, mcl_fp_mont576 }, |
||||
#endif |
||||
}; |
||||
|
||||
FuncOp getFuncOp(size_t bitLen) |
||||
{ |
||||
typedef std::map<size_t, FuncOp> Map; |
||||
static Map map; |
||||
static bool init = false; |
||||
if (!init) { |
||||
init = true; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(gFuncOpTbl); i++) { |
||||
map[gFuncOpTbl[i].bitLen] = gFuncOpTbl[i]; |
||||
} |
||||
} |
||||
for (Map::const_iterator i = map.begin(), ie = map.end(); i != ie; ++i) { |
||||
if (bitLen <= i->second.bitLen) { |
||||
return i->second; |
||||
} |
||||
} |
||||
printf("ERR bitLen=%d\n", (int)bitLen); |
||||
exit(1); |
||||
} |
||||
|
||||
void test(const Unit *p, size_t bitLen) |
||||
{ |
||||
printf("bitLen %d\n", (int)bitLen); |
||||
const size_t n = getUnitN(bitLen); |
||||
#ifdef NDEBUG |
||||
bool doBench = true; |
||||
#else |
||||
bool doBench = false; |
||||
#endif |
||||
const FuncOp funcOp = getFuncOp(bitLen); |
||||
const void4op addS = funcOp.addS; |
||||
const void4op addL = funcOp.addL; |
||||
const void4op subS = funcOp.subS; |
||||
const void4op subL = funcOp.subL; |
||||
const void3op mulPre = funcOp.mulPre; |
||||
const void4Iop mont = funcOp.mont; |
||||
|
||||
mcl::fp::Unit x[MAX_N], y[MAX_N]; |
||||
mcl::fp::Unit z[MAX_N], w[MAX_N]; |
||||
mcl::fp::Unit z2[MAX_N * 2]; |
||||
mcl::fp::Unit w2[MAX_N * 2]; |
||||
cybozu::XorShift rg; |
||||
mcl::fp::getRandVal(x, rg, p, bitLen); |
||||
mcl::fp::getRandVal(y, rg, p, bitLen); |
||||
const size_t C = 10; |
||||
|
||||
addC(z, x, y, p, n); |
||||
addS(w, x, y, p); |
||||
VERIFY_EQUAL(z, w, n); |
||||
for (size_t i = 0; i < C; i++) { |
||||
addC(z, y, z, p, n); |
||||
addS(w, y, w, p); |
||||
VERIFY_EQUAL(z, w, n); |
||||
addC(z, y, z, p, n); |
||||
addL(w, y, w, p); |
||||
VERIFY_EQUAL(z, w, n); |
||||
subC(z, x, z, p, n); |
||||
subS(w, x, w, p); |
||||
VERIFY_EQUAL(z, w, n); |
||||
subC(z, x, z, p, n); |
||||
subL(w, x, w, p); |
||||
VERIFY_EQUAL(z, w, n); |
||||
mulPreC(z2, x, z, n); |
||||
mulPre(w2, x, z); |
||||
VERIFY_EQUAL(z2, w2, n * 2); |
||||
} |
||||
{ |
||||
mpz_class mp; |
||||
setMpz(mp, p, n); |
||||
Montgomery m(mp); |
||||
#ifdef USE_XBYAK |
||||
if (bitLen > 128) fg.init(p, n); |
||||
#endif |
||||
/*
|
||||
real mont |
||||
0 0 |
||||
1 R^-1 |
||||
R 1 |
||||
-1 -R^-1 |
||||
-R -1 |
||||
*/ |
||||
mpz_class t = 1; |
||||
const mpz_class R = (t << (n * 64)) % mp; |
||||
const mpz_class tbl[] = { |
||||
0, 1, R, mp - 1, mp - R |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const mpz_class& mx = tbl[i]; |
||||
for (size_t j = i; j < CYBOZU_NUM_OF_ARRAY(tbl); j++) { |
||||
const mpz_class& my = tbl[j]; |
||||
getMpz(x, n, mx); |
||||
getMpz(y, n, my); |
||||
m.mont(z, x, y); |
||||
mont(w, x, y, p, m.r_); |
||||
VERIFY_EQUAL(z, w, n); |
||||
#ifdef USE_XBYAK |
||||
if (bitLen > 128) { |
||||
fg.mul_(w, x, y); |
||||
VERIFY_EQUAL(z, w, n); |
||||
} |
||||
#endif |
||||
} |
||||
} |
||||
if (doBench) { |
||||
// CYBOZU_BENCH("montC", m.mont, x, y, x);
|
||||
CYBOZU_BENCH("montA ", mont, x, y, x, p, m.r_); |
||||
} |
||||
} |
||||
if (doBench) { |
||||
// CYBOZU_BENCH("addS", addS, x, y, x, p); // slow
|
||||
// CYBOZU_BENCH("subS", subS, x, y, x, p);
|
||||
// CYBOZU_BENCH("addL", addL, x, y, x, p);
|
||||
// CYBOZU_BENCH("subL", subL, x, y, x, p);
|
||||
CYBOZU_BENCH("mulPreA", mulPre, w2, y, x); |
||||
CYBOZU_BENCH("mulPreC", mulPreC, w2, y, x, n); |
||||
CYBOZU_BENCH("modC ", modC, x, w2, p, n); |
||||
} |
||||
#ifdef USE_XBYAK |
||||
if (bitLen <= 128) return; |
||||
if (doBench) { |
||||
fg.init(p, n); |
||||
CYBOZU_BENCH("addA ", fg.add_, x, y, x); |
||||
CYBOZU_BENCH("subA ", fg.sub_, x, y, x); |
||||
// CYBOZU_BENCH("mulA", fg.mul_, x, y, x);
|
||||
} |
||||
#endif |
||||
printf("mont test %d\n", (int)bitLen); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(all) |
||||
{ |
||||
const struct { |
||||
size_t n; |
||||
const uint64_t p[9]; |
||||
} tbl[] = { |
||||
// { 2, { 0xf000000000000001, 1, } },
|
||||
{ 2, { 0x000000000000001d, 0x8000000000000000, } }, |
||||
{ 3, { 0x000000000000012b, 0x0000000000000000, 0x0000000080000000, } }, |
||||
// { 3, { 0x0f69466a74defd8d, 0xfffffffe26f2fc17, 0x07ffffffffffffff, } },
|
||||
// { 3, { 0x7900342423332197, 0x1234567890123456, 0x1480948109481904, } },
|
||||
{ 3, { 0x0f69466a74defd8d, 0xfffffffe26f2fc17, 0xffffffffffffffff, } }, |
||||
// { 4, { 0x7900342423332197, 0x4242342420123456, 0x1234567892342342, 0x1480948109481904, } },
|
||||
// { 4, { 0x0f69466a74defd8d, 0xfffffffe26f2fc17, 0x17ffffffffffffff, 0x1513423423423415, } },
|
||||
{ 4, { 0xa700000000000013, 0x6121000000000013, 0xba344d8000000008, 0x2523648240000001, } }, |
||||
// { 5, { 0x0000000000000009, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8000000000000000, } },
|
||||
{ 5, { 0xfffffffffffffc97, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, } }, |
||||
// { 6, { 0x4720422423332197, 0x0034230847204720, 0x3456789012345679, 0x4820984290482212, 0x9482094820948209, 0x0194810841094810, } },
|
||||
// { 6, { 0x7204224233321972, 0x0342308472047204, 0x4567890123456790, 0x0948204204243123, 0x2098420984209482, 0x2093482094810948, } },
|
||||
{ 6, { 0x00000000ffffffff, 0xffffffff00000000, 0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, } }, |
||||
// { 7, { 0x0000000000000063, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8000000000000000, } },
|
||||
{ 7, { 0x000000000fffcff1, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, } }, |
||||
{ 8, { 0xffffffffffffd0c9, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, } }, |
||||
{ 9, { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x00000000000001ff, } }, |
||||
// { 9, { 0x4720422423332197, 0x0034230847204720, 0x3456789012345679, 0x2498540975555312, 0x9482904924029424, 0x0948209842098402, 0x1098410948109482, 0x0820958209582094, 0x0000000000000029, } },
|
||||
// { 9, { 0x0f69466a74defd8d, 0xfffffffe26f2fc17, 0x7fffffffffffffff, 0x8572938572398583, 0x5732057823857293, 0x9820948205872380, 0x3409238420492034, 0x9483842098340298, 0x0000000000000003, } },
|
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const size_t n = tbl[i].n; |
||||
const size_t bitLen = (n - 1) * 64 + cybozu::bsr<uint64_t>(tbl[i].p[n - 1]) + 1; |
||||
test((const Unit*)tbl[i].p, bitLen); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,397 @@ |
||||
#define PUT(x) std::cout << #x "=" << (x) << std::endl |
||||
#define CYBOZU_TEST_DISABLE_AUTO_RUN |
||||
#include <cybozu/test.hpp> |
||||
#include <cybozu/benchmark.hpp> |
||||
#include <mcl/gmp_util.hpp> |
||||
|
||||
#include <mcl/fp.hpp> |
||||
typedef mcl::FpT<> Fp_3; |
||||
typedef mcl::FpT<> Fp_4; |
||||
typedef mcl::FpT<> Fp_6; |
||||
typedef mcl::FpT<> Fp_9; |
||||
#include <mcl/ec.hpp> |
||||
#include <mcl/ecparam.hpp> |
||||
#include <time.h> |
||||
|
||||
struct tagZn; |
||||
typedef mcl::FpT<tagZn> Zn; |
||||
|
||||
template<class Fp> |
||||
struct Test { |
||||
typedef mcl::EcT<Fp> Ec; |
||||
const mcl::EcParam& para; |
||||
Test(const mcl::EcParam& para) |
||||
: para(para) |
||||
{ |
||||
Fp::setModulo(para.p); |
||||
Zn::setModulo(para.n); |
||||
Ec::setParam(para.a, para.b); |
||||
// CYBOZU_TEST_EQUAL(para.bitLen, Fp(-1).getBitLen());
|
||||
} |
||||
void cstr() const |
||||
{ |
||||
Ec O; |
||||
CYBOZU_TEST_ASSERT(O.isZero()); |
||||
Ec P; |
||||
Ec::neg(P, O); |
||||
CYBOZU_TEST_EQUAL(P, O); |
||||
} |
||||
void ope() const |
||||
{ |
||||
Fp x(para.gx); |
||||
Fp y(para.gy); |
||||
Zn n = 0; |
||||
CYBOZU_TEST_ASSERT(Ec::isValid(x, y)); |
||||
Ec P(x, y), Q, R, O; |
||||
{ |
||||
Ec::neg(Q, P); |
||||
CYBOZU_TEST_EQUAL(Q.x, P.x); |
||||
CYBOZU_TEST_EQUAL(Q.y, -P.y); |
||||
|
||||
R = P + Q; |
||||
CYBOZU_TEST_ASSERT(R.isZero()); |
||||
|
||||
R = P + O; |
||||
CYBOZU_TEST_EQUAL(R, P); |
||||
R = O + P; |
||||
CYBOZU_TEST_EQUAL(R, P); |
||||
} |
||||
|
||||
{ |
||||
Ec::dbl(R, P); |
||||
Ec R2 = P + P; |
||||
CYBOZU_TEST_EQUAL(R, R2); |
||||
{ |
||||
Ec P2 = P; |
||||
Ec::dbl(P2, P2); |
||||
CYBOZU_TEST_EQUAL(P2, R2); |
||||
} |
||||
Ec R3L = R2 + P; |
||||
Ec R3R = P + R2; |
||||
CYBOZU_TEST_EQUAL(R3L, R3R); |
||||
{ |
||||
Ec RR = R2; |
||||
RR = RR + P; |
||||
CYBOZU_TEST_EQUAL(RR, R3L); |
||||
RR = R2; |
||||
RR = P + RR; |
||||
CYBOZU_TEST_EQUAL(RR, R3L); |
||||
RR = P; |
||||
RR = RR + RR; |
||||
CYBOZU_TEST_EQUAL(RR, R2); |
||||
} |
||||
Ec::power(R, P, 2); |
||||
CYBOZU_TEST_EQUAL(R, R2); |
||||
Ec R4L = R3L + R2; |
||||
Ec R4R = R2 + R3L; |
||||
CYBOZU_TEST_EQUAL(R4L, R4R); |
||||
Ec::power(R, P, 5); |
||||
CYBOZU_TEST_EQUAL(R, R4L); |
||||
} |
||||
{ |
||||
R = P; |
||||
for (int i = 0; i < 10; i++) { |
||||
R += P; |
||||
} |
||||
Ec R2; |
||||
Ec::power(R2, P, 11); |
||||
CYBOZU_TEST_EQUAL(R, R2); |
||||
} |
||||
Ec::power(R, P, n - 1); |
||||
CYBOZU_TEST_EQUAL(R, -P); |
||||
R += P; // Ec::power(R, P, n);
|
||||
CYBOZU_TEST_ASSERT(R.isZero()); |
||||
} |
||||
|
||||
void power() const |
||||
{ |
||||
Fp x(para.gx); |
||||
Fp y(para.gy); |
||||
Ec P(x, y); |
||||
Ec Q; |
||||
Ec R; |
||||
for (int i = 0; i < 100; i++) { |
||||
Ec::power(Q, P, i); |
||||
CYBOZU_TEST_EQUAL(Q, R); |
||||
R += P; |
||||
} |
||||
} |
||||
|
||||
void neg_power() const |
||||
{ |
||||
Fp x(para.gx); |
||||
Fp y(para.gy); |
||||
Ec P(x, y); |
||||
Ec Q; |
||||
Ec R; |
||||
for (int i = 0; i < 100; i++) { |
||||
Ec::power(Q, P, -i); |
||||
CYBOZU_TEST_EQUAL(Q, R); |
||||
R -= P; |
||||
} |
||||
} |
||||
void squareRoot() const |
||||
{ |
||||
Fp x(para.gx); |
||||
Fp y(para.gy); |
||||
bool odd = Fp::isYodd(y); |
||||
Fp yy; |
||||
Ec::getYfromX(yy, x, odd); |
||||
CYBOZU_TEST_EQUAL(yy, y); |
||||
Fp::neg(y, y); |
||||
odd = Fp::isYodd(y); |
||||
yy.clear(); |
||||
Ec::getYfromX(yy, x, odd); |
||||
CYBOZU_TEST_EQUAL(yy, y); |
||||
} |
||||
void power_fp() const |
||||
{ |
||||
Fp x(para.gx); |
||||
Fp y(para.gy); |
||||
Ec P(x, y); |
||||
Ec Q; |
||||
Ec R; |
||||
for (int i = 0; i < 100; i++) { |
||||
Ec::power(Q, P, Zn(i)); |
||||
CYBOZU_TEST_EQUAL(Q, R); |
||||
R += P; |
||||
} |
||||
} |
||||
void binaryExpression() const |
||||
{ |
||||
puts("test binaryExpression"); |
||||
const Fp x(para.gx); |
||||
const Fp y(para.gy); |
||||
Ec P(x, y); |
||||
Ec Q; |
||||
// not compressed
|
||||
Ec::setCompressedExpression(false); |
||||
{ |
||||
cybozu::BitVector bv; |
||||
P.appendToBitVec(bv); |
||||
Q.fromBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
{ |
||||
P = -P; |
||||
cybozu::BitVector bv; |
||||
P.appendToBitVec(bv); |
||||
Q.fromBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
P.clear(); |
||||
{ |
||||
cybozu::BitVector bv; |
||||
P.appendToBitVec(bv); |
||||
Q.fromBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
// compressed
|
||||
Ec::setCompressedExpression(true); |
||||
P.set(x, y); |
||||
{ |
||||
cybozu::BitVector bv; |
||||
P.appendToBitVec(bv); |
||||
Q.fromBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
{ |
||||
P = -P; |
||||
cybozu::BitVector bv; |
||||
P.appendToBitVec(bv); |
||||
Q.fromBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
P.clear(); |
||||
{ |
||||
cybozu::BitVector bv; |
||||
P.appendToBitVec(bv); |
||||
Q.fromBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
} |
||||
void str() const |
||||
{ |
||||
puts("test str"); |
||||
const Fp x(para.gx); |
||||
const Fp y(para.gy); |
||||
Ec P(x, y); |
||||
Ec Q; |
||||
// not compressed
|
||||
Ec::setCompressedExpression(false); |
||||
{ |
||||
std::stringstream ss; |
||||
ss << P; |
||||
ss >> Q; |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
{ |
||||
P = -P; |
||||
std::stringstream ss; |
||||
ss << P; |
||||
ss >> Q; |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
P.clear(); |
||||
{ |
||||
std::stringstream ss; |
||||
ss << P; |
||||
ss >> Q; |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
// compressed
|
||||
Ec::setCompressedExpression(true); |
||||
P.set(x, y); |
||||
{ |
||||
std::stringstream ss; |
||||
ss << P; |
||||
ss >> Q; |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
{ |
||||
P = -P; |
||||
std::stringstream ss; |
||||
ss << P; |
||||
ss >> Q; |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
P.clear(); |
||||
{ |
||||
std::stringstream ss; |
||||
ss << P; |
||||
ss >> Q; |
||||
CYBOZU_TEST_EQUAL(P, Q); |
||||
} |
||||
} |
||||
|
||||
template<class F> |
||||
void test(F f, const char *msg) const |
||||
{ |
||||
const int N = 300000; |
||||
Fp x(para.gx); |
||||
Fp y(para.gy); |
||||
Ec P(x, y); |
||||
Ec Q = P + P + P; |
||||
clock_t begin = clock(); |
||||
for (int i = 0; i < N; i++) { |
||||
f(Q, P, Q); |
||||
} |
||||
clock_t end = clock(); |
||||
printf("%s %.2fusec\n", msg, (end - begin) / double(CLOCKS_PER_SEC) / N * 1e6); |
||||
} |
||||
/*
|
||||
add 8.71usec -> 6.94 |
||||
sub 6.80usec -> 4.84 |
||||
dbl 9.59usec -> 7.75 |
||||
pos 2730usec -> 2153 |
||||
*/ |
||||
void bench() const |
||||
{ |
||||
Fp x(para.gx); |
||||
Fp y(para.gy); |
||||
Ec P(x, y); |
||||
Ec Q = P + P + P; |
||||
CYBOZU_BENCH("add", Ec::add, Q, P, Q); |
||||
CYBOZU_BENCH("sub", Ec::sub, Q, P, Q); |
||||
CYBOZU_BENCH("dbl", Ec::dbl, P, P); |
||||
Zn z("-3"); |
||||
CYBOZU_BENCH("pow", Ec::power, P, P, z); |
||||
} |
||||
/*
|
||||
Affine : sandy-bridge |
||||
add 3.17usec |
||||
sub 2.43usec |
||||
dbl 3.32usec |
||||
pow 905.00usec |
||||
Jacobi |
||||
add 2.34usec |
||||
sub 2.65usec |
||||
dbl 1.56usec |
||||
pow 499.00usec |
||||
*/ |
||||
void run() const |
||||
{ |
||||
cstr(); |
||||
ope(); |
||||
power(); |
||||
neg_power(); |
||||
power_fp(); |
||||
binaryExpression(); |
||||
squareRoot(); |
||||
str(); |
||||
#ifdef NDEBUG |
||||
bench(); |
||||
#endif |
||||
} |
||||
private: |
||||
Test(const Test&); |
||||
void operator=(const Test&); |
||||
}; |
||||
|
||||
template<class Fp> |
||||
void test_sub(const mcl::EcParam *para, size_t paraNum) |
||||
{ |
||||
for (size_t i = 0; i < paraNum; i++) { |
||||
puts(para[i].name); |
||||
Test<Fp>(para[i]).run(); |
||||
} |
||||
} |
||||
|
||||
int g_partial = -1; |
||||
|
||||
CYBOZU_TEST_AUTO(all) |
||||
{ |
||||
#ifdef USE_MONT_FP |
||||
puts("use MontFp"); |
||||
#else |
||||
puts("use GMP"); |
||||
#endif |
||||
if (g_partial & (1 << 3)) { |
||||
const struct mcl::EcParam para3[] = { |
||||
// mcl::ecparam::p160_1,
|
||||
mcl::ecparam::secp160k1, |
||||
mcl::ecparam::secp192k1, |
||||
mcl::ecparam::NIST_P192, |
||||
}; |
||||
test_sub<Fp_3>(para3, CYBOZU_NUM_OF_ARRAY(para3)); |
||||
} |
||||
|
||||
if (g_partial & (1 << 4)) { |
||||
const struct mcl::EcParam para4[] = { |
||||
mcl::ecparam::secp224k1, |
||||
mcl::ecparam::secp256k1, |
||||
mcl::ecparam::NIST_P224, |
||||
mcl::ecparam::NIST_P256, |
||||
}; |
||||
test_sub<Fp_4>(para4, CYBOZU_NUM_OF_ARRAY(para4)); |
||||
} |
||||
|
||||
if (g_partial & (1 << 6)) { |
||||
const struct mcl::EcParam para6[] = { |
||||
// mcl::ecparam::secp384r1,
|
||||
mcl::ecparam::NIST_P384, |
||||
}; |
||||
test_sub<Fp_6>(para6, CYBOZU_NUM_OF_ARRAY(para6)); |
||||
} |
||||
|
||||
if (g_partial & (1 << 9)) { |
||||
const struct mcl::EcParam para9[] = { |
||||
// mcl::ecparam::secp521r1,
|
||||
mcl::ecparam::NIST_P521, |
||||
}; |
||||
test_sub<Fp_9>(para9, CYBOZU_NUM_OF_ARRAY(para9)); |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
if (argc == 1) { |
||||
g_partial = -1; |
||||
} else { |
||||
g_partial = 0; |
||||
for (int i = 1; i < argc; i++) { |
||||
g_partial |= 1 << atoi(argv[i]); |
||||
} |
||||
} |
||||
return cybozu::test::autoRun.run(argc, argv); |
||||
} |
@ -0,0 +1,222 @@ |
||||
#include <cybozu/test.hpp> |
||||
#if CYBOZU_OS_BIT == 32 |
||||
// not support
|
||||
#else |
||||
#include <mcl/gmp_util.hpp> |
||||
#include <stdint.h> |
||||
#include <string> |
||||
#include <cybozu/itoa.hpp> |
||||
#include <mcl/fp_generator.hpp> |
||||
#include <mcl/fp.hpp> |
||||
#include <iostream> |
||||
#include <cybozu/xorshift.hpp> |
||||
#include <cybozu/benchmark.hpp> |
||||
|
||||
typedef mcl::FpT<> Fp; |
||||
|
||||
const int MAX_N = 4; |
||||
|
||||
const char *primeTable[] = { |
||||
"7fffffffffffffffffffffffffffffff", // 127bit(not full)
|
||||
"ffffffffffffffffffffffffffffff61", // 128bit(full)
|
||||
"fffffffffffffffffffffffffffffffffffffffeffffee37", // 192bit(full)
|
||||
"2523648240000001ba344d80000000086121000000000013a700000000000013", // 254bit(not full)
|
||||
}; |
||||
|
||||
/*
|
||||
p is output buffer |
||||
pStr is hex |
||||
return the size of p |
||||
*/ |
||||
int convertToArray(uint64_t *p, const mpz_class& x) |
||||
{ |
||||
const int pn = int(sizeof(mp_limb_t) * x.get_mpz_t()->_mp_size / sizeof(*p)); |
||||
if (pn > MAX_N) { |
||||
printf("pn(%d) is too large\n", pn); |
||||
exit(1); |
||||
} |
||||
const uint64_t *q = (const uint64_t*)x.get_mpz_t()->_mp_d; |
||||
std::copy(q, q + pn, p); |
||||
std::fill(p + pn, p + MAX_N, 0); |
||||
return pn; |
||||
} |
||||
int convertToArray(uint64_t *p, const char *pStr) |
||||
{ |
||||
mpz_class x; |
||||
x.set_str(pStr, 16); |
||||
return convertToArray(p, x); |
||||
} |
||||
|
||||
struct Int { |
||||
int vn; |
||||
uint64_t v[MAX_N]; |
||||
Int() |
||||
: vn(0) |
||||
{ |
||||
} |
||||
explicit Int(int vn) |
||||
{ |
||||
if (vn > MAX_N) { |
||||
printf("vn(%d) is too large\n", vn); |
||||
exit(1); |
||||
} |
||||
this->vn = vn; |
||||
} |
||||
void set(const char *str) { fromStr(str); } |
||||
void set(const Fp& rhs) |
||||
{ |
||||
convertToArray(v, rhs.toGmp()); |
||||
} |
||||
void set(const uint64_t* x) |
||||
{ |
||||
for (int i = 0; i < vn; i++) v[i] = x[i]; |
||||
} |
||||
void fromStr(const char *str) |
||||
{ |
||||
convertToArray(v, str); |
||||
} |
||||
std::string toStr() const |
||||
{ |
||||
std::string ret; |
||||
for (int i = 0; i < vn; i++) { |
||||
ret += cybozu::itohex(v[vn - 1 - i], false); |
||||
} |
||||
return ret; |
||||
} |
||||
void put(const char *msg = "") const |
||||
{ |
||||
if (msg) printf("%s=", msg); |
||||
printf("%s\n", toStr().c_str()); |
||||
} |
||||
bool operator==(const Int& rhs) const |
||||
{ |
||||
if (vn != rhs.vn) return false; |
||||
for (int i = 0; i < vn; i++) { |
||||
if (v[i] != rhs.v[i]) return false; |
||||
} |
||||
return true; |
||||
} |
||||
bool operator!=(const Int& rhs) const { return !operator==(rhs); } |
||||
bool operator==(const Fp& rhs) const |
||||
{ |
||||
Int t(vn); |
||||
t.set(rhs); |
||||
return operator==(t); |
||||
} |
||||
bool operator!=(const Fp& rhs) const { return !operator==(rhs); } |
||||
}; |
||||
static inline std::ostream& operator<<(std::ostream& os, const Int& x) |
||||
{ |
||||
return os << x.toStr(); |
||||
} |
||||
|
||||
void testAddSub(const mcl::FpGenerator& fg, int pn) |
||||
{ |
||||
Fp x, y; |
||||
Int mx(pn), my(pn); |
||||
x.fromStr("0x8811aabb23427cc"); |
||||
y.fromStr("0x8811aabb23427cc11"); |
||||
mx.set(x); |
||||
my.set(y); |
||||
for (int i = 0; i < 30; i++) { |
||||
CYBOZU_TEST_EQUAL(mx, x); |
||||
x += x; |
||||
fg.add_(mx.v, mx.v, mx.v); |
||||
} |
||||
for (int i = 0; i < 30; i++) { |
||||
CYBOZU_TEST_EQUAL(mx, x); |
||||
x += y; |
||||
fg.add_(mx.v, mx.v, my.v); |
||||
} |
||||
for (int i = 0; i < 30; i++) { |
||||
CYBOZU_TEST_EQUAL(my, y); |
||||
y -= x; |
||||
fg.sub_(my.v, my.v, mx.v); |
||||
} |
||||
} |
||||
|
||||
void testNeg(const mcl::FpGenerator& fg, int pn) |
||||
{ |
||||
Fp x; |
||||
Int mx(pn), my(pn); |
||||
const char *tbl[] = { |
||||
"0", |
||||
"0x12346", |
||||
"0x11223344556677881122334455667788", |
||||
"0x0abbccddeeffaabb0000000000000000", |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
x.fromStr(tbl[i]); |
||||
mx.set(x); |
||||
x = -x; |
||||
fg.neg_(mx.v, mx.v); |
||||
CYBOZU_TEST_EQUAL(mx, x); |
||||
} |
||||
} |
||||
|
||||
void testMulI(const mcl::FpGenerator& fg, int pn) |
||||
{ |
||||
cybozu::XorShift rg; |
||||
for (int i = 0; i < 100; i++) { |
||||
uint64_t x[MAX_N]; |
||||
uint64_t z[MAX_N + 1]; |
||||
rg.read(x, pn); |
||||
uint64_t y = rg.get64(); |
||||
mpz_class mx; |
||||
mcl::Gmp::setRaw(mx, x, pn); |
||||
mpz_class my; |
||||
mcl::Gmp::set(my, y); |
||||
mx *= my; |
||||
uint64_t d = fg.mulI_(z, x, y); |
||||
z[pn] = d; |
||||
mcl::Gmp::setRaw(my, z, pn + 1); |
||||
CYBOZU_TEST_EQUAL(mx, my); |
||||
} |
||||
{ |
||||
uint64_t x[MAX_N]; |
||||
uint64_t z[MAX_N + 1]; |
||||
rg.read(x, pn); |
||||
uint64_t y = rg.get64(); |
||||
CYBOZU_BENCH_C("mulI", 10000000, fg.mulI_, z, x, y); |
||||
} |
||||
} |
||||
|
||||
void testShr1(const mcl::FpGenerator& fg, int pn) |
||||
{ |
||||
cybozu::XorShift rg; |
||||
for (int i = 0; i < 100; i++) { |
||||
uint64_t x[MAX_N]; |
||||
uint64_t z[MAX_N]; |
||||
rg.read(x, pn); |
||||
mpz_class mx; |
||||
mcl::Gmp::setRaw(mx, x, pn); |
||||
mx >>= 1; |
||||
fg.shr1_(z, x); |
||||
mpz_class my; |
||||
mcl::Gmp::setRaw(my, z, pn); |
||||
CYBOZU_TEST_EQUAL(mx, my); |
||||
} |
||||
} |
||||
|
||||
void test(const char *pStr) |
||||
{ |
||||
Fp::setModulo(pStr, 16); |
||||
uint64_t p[MAX_N]; |
||||
const int pn = convertToArray(p, pStr); |
||||
printf("pn=%d\n", pn); |
||||
mcl::FpGenerator fg; |
||||
fg.init(p, pn); |
||||
testAddSub(fg, pn); |
||||
testNeg(fg, pn); |
||||
testMulI(fg, pn); |
||||
testShr1(fg, pn); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(all) |
||||
{ |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(primeTable); i++) { |
||||
printf("test prime i=%d\n", (int)i); |
||||
test(primeTable[i]); |
||||
} |
||||
} |
||||
#endif |
@ -0,0 +1,465 @@ |
||||
#define PUT(x) std::cout << #x "=" << (x) << std::endl |
||||
#include <cybozu/test.hpp> |
||||
#include <mcl/fp.hpp> |
||||
#include <cybozu/benchmark.hpp> |
||||
#include <time.h> |
||||
|
||||
#ifdef _MSC_VER |
||||
#pragma warning(disable: 4127) // const condition
|
||||
#endif |
||||
|
||||
typedef mcl::FpT<> Fp; |
||||
|
||||
const int m = 65537; |
||||
struct Init { |
||||
Init() |
||||
{ |
||||
std::ostringstream ms; |
||||
ms << m; |
||||
Fp::setModulo(ms.str()); |
||||
} |
||||
}; |
||||
|
||||
CYBOZU_TEST_SETUP_FIXTURE(Init); |
||||
|
||||
#ifndef MCL_ONLY_BENCH |
||||
CYBOZU_TEST_AUTO(cstr) |
||||
{ |
||||
const struct { |
||||
const char *str; |
||||
int val; |
||||
} tbl[] = { |
||||
{ "0", 0 }, |
||||
{ "1", 1 }, |
||||
{ "123", 123 }, |
||||
{ "0x123", 0x123 }, |
||||
{ "0b10101", 21 }, |
||||
{ "-123", m - 123 }, |
||||
{ "-0x123", m - 0x123 }, |
||||
{ "-0b10101", m - 21 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
// string cstr
|
||||
Fp x(tbl[i].str); |
||||
CYBOZU_TEST_EQUAL(x, tbl[i].val); |
||||
|
||||
// int cstr
|
||||
Fp y(tbl[i].val); |
||||
CYBOZU_TEST_EQUAL(y, x); |
||||
|
||||
// copy cstr
|
||||
Fp z(x); |
||||
CYBOZU_TEST_EQUAL(z, x); |
||||
|
||||
// assign int
|
||||
Fp w; |
||||
w = tbl[i].val; |
||||
CYBOZU_TEST_EQUAL(w, x); |
||||
|
||||
// assign self
|
||||
Fp u; |
||||
u = w; |
||||
CYBOZU_TEST_EQUAL(u, x); |
||||
|
||||
// conv
|
||||
std::ostringstream os; |
||||
os << tbl[i].val; |
||||
|
||||
std::string str; |
||||
x.toStr(str); |
||||
CYBOZU_TEST_EQUAL(str, os.str()); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(fromStr) |
||||
{ |
||||
const struct { |
||||
const char *in; |
||||
int out; |
||||
int base; |
||||
} tbl[] = { |
||||
{ "100", 100, 0 }, // set base = 10 if base = 0
|
||||
{ "100", 4, 2 }, |
||||
{ "100", 256, 16 }, |
||||
{ "0b100", 4, 0 }, |
||||
{ "0b100", 4, 2 }, |
||||
{ "0x100", 256, 0 }, |
||||
{ "0x100", 256, 16 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
Fp x; |
||||
x.fromStr(tbl[i].in, tbl[i].base); |
||||
CYBOZU_TEST_EQUAL(x, tbl[i].out); |
||||
} |
||||
// conflict prefix with base
|
||||
Fp x; |
||||
CYBOZU_TEST_EXCEPTION(x.fromStr("0b100", 16), cybozu::Exception); |
||||
CYBOZU_TEST_EXCEPTION(x.fromStr("0x100", 2), cybozu::Exception); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(stream) |
||||
{ |
||||
const struct { |
||||
const char *in; |
||||
int out10; |
||||
int out16; |
||||
} tbl[] = { |
||||
{ "100", 100, 256 }, // set base = 10 if base = 0
|
||||
{ "0x100", 256, 256 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
{ |
||||
std::istringstream is(tbl[i].in); |
||||
Fp x; |
||||
is >> x; |
||||
CYBOZU_TEST_EQUAL(x, tbl[i].out10); |
||||
} |
||||
{ |
||||
std::istringstream is(tbl[i].in); |
||||
Fp x; |
||||
is >> std::hex >> x; |
||||
CYBOZU_TEST_EQUAL(x, tbl[i].out16); |
||||
} |
||||
} |
||||
std::istringstream is("0b100"); |
||||
Fp x; |
||||
CYBOZU_TEST_EXCEPTION(is >> std::hex >> x, cybozu::Exception); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(conv) |
||||
{ |
||||
const char *bin = "0b1001000110100"; |
||||
const char *hex = "0x1234"; |
||||
const char *dec = "4660"; |
||||
Fp b(bin); |
||||
Fp h(hex); |
||||
Fp d(dec); |
||||
CYBOZU_TEST_EQUAL(b, h); |
||||
CYBOZU_TEST_EQUAL(b, d); |
||||
|
||||
std::string str; |
||||
b.toStr(str, 2, true); |
||||
CYBOZU_TEST_EQUAL(str, bin); |
||||
b.toStr(str); |
||||
CYBOZU_TEST_EQUAL(str, dec); |
||||
b.toStr(str, 16, true); |
||||
CYBOZU_TEST_EQUAL(str, hex); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(compare) |
||||
{ |
||||
const struct { |
||||
int lhs; |
||||
int rhs; |
||||
int cmp; |
||||
} tbl[] = { |
||||
{ 0, 0, 0 }, |
||||
{ 1, 0, 1 }, |
||||
{ 0, 1, -1 }, |
||||
{ -1, 0, 1 }, // m-1, 0
|
||||
{ 0, -1, -1 }, // 0, m-1
|
||||
{ 123, 456, -1 }, |
||||
{ 456, 123, 1 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const Fp x(tbl[i].lhs); |
||||
const Fp y(tbl[i].rhs); |
||||
const int cmp = tbl[i].cmp; |
||||
if (cmp == 0) { |
||||
CYBOZU_TEST_EQUAL(x, y); |
||||
} else { |
||||
CYBOZU_TEST_ASSERT(x != y); |
||||
} |
||||
} |
||||
{ |
||||
Fp x(5); |
||||
CYBOZU_TEST_ASSERT(x == 5); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(modulo) |
||||
{ |
||||
std::ostringstream ms; |
||||
ms << m; |
||||
|
||||
std::string str; |
||||
Fp::getModulo(str); |
||||
CYBOZU_TEST_EQUAL(str, ms.str()); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(ope) |
||||
{ |
||||
const struct { |
||||
int x; |
||||
int y; |
||||
int add; // x + y
|
||||
int sub; // x - y
|
||||
int mul; // x * y
|
||||
int sqr; // x^2
|
||||
} tbl[] = { |
||||
{ 0, 1, 1, m - 1, 0, 0 }, |
||||
{ 9, 5, 14, 4, 45, 81 }, |
||||
{ 10, 13, 23, m - 3, 130, 100 }, |
||||
{ 2000, 1000, 3000, 1000, (2000 * 1000) % m, (2000 * 2000) % m }, |
||||
{ 12345, 9999, 12345 + 9999, 12345 - 9999, (12345 * 9999) % m, (12345 * 12345) % m }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const Fp x(tbl[i].x); |
||||
const Fp y(tbl[i].y); |
||||
Fp z; |
||||
Fp::add(z, x, y); |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].add); |
||||
Fp::sub(z, x, y); |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].sub); |
||||
Fp::mul(z, x, y); |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].mul); |
||||
|
||||
Fp r; |
||||
Fp::inv(r, y); |
||||
Fp::mul(z, z, r); |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].x); |
||||
z = x + y; |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].add); |
||||
z = x - y; |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].sub); |
||||
z = x * y; |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].mul); |
||||
|
||||
Fp::square(z, x); |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].sqr); |
||||
|
||||
z = x / y; |
||||
z *= y; |
||||
CYBOZU_TEST_EQUAL(z, tbl[i].x); |
||||
} |
||||
} |
||||
|
||||
struct tag2; |
||||
|
||||
CYBOZU_TEST_AUTO(power) |
||||
{ |
||||
Fp x, y, z; |
||||
x = 12345; |
||||
z = 1; |
||||
for (int i = 0; i < 100; i++) { |
||||
Fp::power(y, x, i); |
||||
CYBOZU_TEST_EQUAL(y, z); |
||||
z *= x; |
||||
} |
||||
typedef mcl::FpT<tag2, 128> Fp2; |
||||
Fp2::setModulo("1009"); |
||||
x = 5; |
||||
Fp2 n = 3; |
||||
z = 3; |
||||
Fp::power(x, x, z); |
||||
CYBOZU_TEST_EQUAL(x, 125); |
||||
x = 5; |
||||
Fp::power(x, x, n); |
||||
CYBOZU_TEST_EQUAL(x, 125); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(power_fp) |
||||
{ |
||||
Fp x, y, z; |
||||
x = 12345; |
||||
z = 1; |
||||
for (int i = 0; i < 100; i++) { |
||||
Fp::power(y, x, Fp(i)); |
||||
CYBOZU_TEST_EQUAL(y, z); |
||||
z *= x; |
||||
} |
||||
} |
||||
|
||||
struct TagAnother; |
||||
|
||||
CYBOZU_TEST_AUTO(another) |
||||
{ |
||||
typedef mcl::FpT<TagAnother, 128> G; |
||||
G::setModulo("13"); |
||||
G a = 3; |
||||
G b = 9; |
||||
a *= b; |
||||
CYBOZU_TEST_EQUAL(a, 1); |
||||
} |
||||
|
||||
|
||||
CYBOZU_TEST_AUTO(setRaw) |
||||
{ |
||||
Fp::setModulo("1000000000000000000117"); |
||||
char b1[] = { 0x56, 0x34, 0x12 }; |
||||
Fp x; |
||||
x.setRaw(b1, 3); |
||||
CYBOZU_TEST_EQUAL(x, 0x123456); |
||||
int b2[] = { 0x12, 0x34 }; |
||||
x.setRaw(b2, 2); |
||||
CYBOZU_TEST_EQUAL(x, Fp("0x3400000012")); |
||||
x.fromStr("0xffffffffffff"); |
||||
|
||||
Fp::setModulo("0x10000000000001234567a5"); |
||||
const struct { |
||||
uint32_t buf[3]; |
||||
size_t bufN; |
||||
const char *expected; |
||||
} tbl[] = { |
||||
{ { 0x234567a4, 0x00000001, 0x00100000}, 1, "0x234567a4" }, |
||||
{ { 0x234567a4, 0x00000001, 0x00100000}, 2, "0x1234567a4" }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
x.setRaw(tbl[i].buf, tbl[i].bufN); |
||||
CYBOZU_TEST_EQUAL(x, Fp(tbl[i].expected)); |
||||
} |
||||
uint32_t large[3] = { 0x234567a5, 0x00000001, 0x00100000}; |
||||
CYBOZU_TEST_EXCEPTION(x.setRaw(large, 3), cybozu::Exception); |
||||
} |
||||
|
||||
|
||||
CYBOZU_TEST_AUTO(set64bit) |
||||
{ |
||||
Fp::setModulo("0x1000000000000000000f"); |
||||
const struct { |
||||
const char *p; |
||||
int64_t i; |
||||
} tbl[] = { |
||||
{ "0x1234567812345678", int64_t(0x1234567812345678ull) }, |
||||
{ "0xfffedcba987edcba997", -int64_t(0x1234567812345678ull) }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
Fp x(tbl[i].p); |
||||
Fp y(tbl[i].i); |
||||
CYBOZU_TEST_EQUAL(x, y); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(getRaw) |
||||
{ |
||||
const struct { |
||||
const char *s; |
||||
uint32_t v[4]; |
||||
size_t vn; |
||||
} tbl[] = { |
||||
{ "0", { 0, 0, 0, 0 }, 1 }, |
||||
{ "1234", { 1234, 0, 0, 0 }, 1 }, |
||||
{ "0xaabbccdd12345678", { 0x12345678, 0xaabbccdd, 0, 0 }, 2 }, |
||||
{ "0x11112222333344445555666677778888", { 0x77778888, 0x55556666, 0x33334444, 0x11112222 }, 4 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
mpz_class x(tbl[i].s); |
||||
const size_t bufN = 8; |
||||
uint32_t buf[bufN]; |
||||
size_t n = mcl::Gmp::getRaw(buf, bufN, x); |
||||
CYBOZU_TEST_EQUAL(n, tbl[i].vn); |
||||
CYBOZU_TEST_EQUAL_ARRAY(buf, tbl[i].v, n); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(toStr) |
||||
{ |
||||
const char *tbl[] = { |
||||
"0x0", |
||||
"0x5", |
||||
"0x123", |
||||
"0x123456789012345679adbc", |
||||
"0xffffffff26f2fc170f69466a74defd8d", |
||||
"0x100000000000000000000000000000033", |
||||
"0x11ee12312312940000000000000000000000000002342343" |
||||
}; |
||||
Fp::setModulo("0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d"); |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
mpz_class x(tbl[i]); |
||||
Fp y(tbl[i]); |
||||
std::string xs, ys; |
||||
mcl::Gmp::toStr(xs, x, 16); |
||||
y.toStr(ys, 16); |
||||
CYBOZU_TEST_EQUAL(xs, ys); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(binaryRepl) |
||||
{ |
||||
const struct { |
||||
const char *s; |
||||
size_t n; |
||||
uint32_t v[6]; |
||||
} tbl[] = { |
||||
{ "0", 0, { 0, 0, 0, 0, 0 } }, |
||||
{ "1234", 1, { 1234, 0, 0, 0, 0 } }, |
||||
{ "0xaabbccdd12345678", 2, { 0x12345678, 0xaabbccdd, 0, 0, 0 } }, |
||||
{ "0x11112222333344445555666677778888", 4, { 0x77778888, 0x55556666, 0x33334444, 0x11112222, 0 } }, |
||||
{ "0x9911112222333344445555666677778888", 5, { 0x77778888, 0x55556666, 0x33334444, 0x11112222, 0x99, 0 } }, |
||||
}; |
||||
Fp::setModulo("0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d"); |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
Fp x(tbl[i].s); |
||||
cybozu::BitVector bv; |
||||
x.appendToBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(bv.size(), Fp::getModBitLen()); |
||||
CYBOZU_TEST_EQUAL(bv.size(), Fp::getBitVecSize()); |
||||
const Fp::BlockType *block = bv.getBlock(); |
||||
if (sizeof(Fp::BlockType) == 4) { |
||||
CYBOZU_TEST_EQUAL_ARRAY(block, tbl[i].v, tbl[i].n); |
||||
} else { |
||||
const size_t n = (tbl[i].n + 1) / 2; |
||||
for (size_t j = 0; j < n; j++) { |
||||
uint64_t v = (uint64_t(tbl[i].v[j * 2 + 1]) << 32) | tbl[i].v[j * 2]; |
||||
CYBOZU_TEST_EQUAL(block[j], v); |
||||
} |
||||
} |
||||
Fp y; |
||||
y.fromBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(x, y); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
#ifdef NDEBUG |
||||
void benchSub(const char *pStr, const char *xStr, const char *yStr) |
||||
try |
||||
{ |
||||
Fp::setModulo(pStr); |
||||
Fp x(xStr); |
||||
Fp y(yStr); |
||||
|
||||
CYBOZU_BENCH("add", Fp::add, x, x, x); |
||||
CYBOZU_BENCH("sub", Fp::sub, x, x, y); |
||||
CYBOZU_BENCH("mul", Fp::mul, x, x, x); |
||||
CYBOZU_BENCH("square", Fp::square, x, x); |
||||
CYBOZU_BENCH("inv", x += y;Fp::inv, x, x); // avoid same jmp
|
||||
CYBOZU_BENCH("div", x += y;Fp::div, x, y, x); |
||||
puts(""); |
||||
} catch (std::exception& e) { |
||||
printf("ERR %s\n", e.what()); |
||||
} |
||||
|
||||
// square 76clk@sandy
|
||||
CYBOZU_TEST_AUTO(bench3) |
||||
{ |
||||
const char *pStr = "0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d"; |
||||
const char *xStr = "0x148094810948190412345678901234567900342423332197"; |
||||
const char *yStr = "0x7fffffffffffffffffffffe26f2fc170f69466a74defd8d"; |
||||
benchSub(pStr, xStr, yStr); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(bench4) |
||||
{ |
||||
const char *pStr = "0x2523648240000001ba344d80000000086121000000000013a700000000000013"; |
||||
const char *xStr = "0x1480948109481904123456789234234242423424201234567900342423332197"; |
||||
const char *yStr = "0x151342342342341517fffffffffffffffffffffe26f2fc170f69466a74defd8d"; |
||||
benchSub(pStr, xStr, yStr); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(bench6) |
||||
{ |
||||
const char *pStr = "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"; |
||||
const char *xStr = "0x19481084109481094820948209482094820984290482212345678901234567900342308472047204720422423332197"; |
||||
const char *yStr = "0x209348209481094820984209842094820948204204243123456789012345679003423084720472047204224233321972"; |
||||
benchSub(pStr, xStr, yStr); |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(bench9) |
||||
{ |
||||
const char *pStr = "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; |
||||
const char *xStr = "0x2908209582095820941098410948109482094820984209840294829049240294242498540975555312345678901234567900342308472047204720422423332197"; |
||||
const char *yStr = "0x3948384209834029834092384204920349820948205872380573205782385729385729385723985837ffffffffffffffffffffffe26f2fc170f69466a74defd8d"; |
||||
benchSub(pStr, xStr, yStr); |
||||
} |
||||
#endif |
@ -0,0 +1,191 @@ |
||||
#define PUT(x) std::cout << #x "=" << (x) << std::endl |
||||
#include <mcl/fp_util.hpp> |
||||
#include <cybozu/test.hpp> |
||||
|
||||
CYBOZU_TEST_AUTO(toStr16) |
||||
{ |
||||
const struct { |
||||
uint32_t x[4]; |
||||
size_t n; |
||||
const char *str; |
||||
} tbl[] = { |
||||
{ { 0, 0, 0, 0 }, 0, "0" }, |
||||
{ { 0x123, 0, 0, 0 }, 1, "123" }, |
||||
{ { 0x12345678, 0xaabbcc, 0, 0 }, 2, "aabbcc12345678" }, |
||||
{ { 0, 0x12, 0x234a, 0 }, 3, "234a0000001200000000" }, |
||||
{ { 1, 2, 0xffffffff, 0x123abc }, 4, "123abcffffffff0000000200000001" }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
std::string str; |
||||
mcl::fp::toStr16(str, tbl[i].x, tbl[i].n, false); |
||||
CYBOZU_TEST_EQUAL(str, tbl[i].str); |
||||
mcl::fp::toStr16(str, tbl[i].x, tbl[i].n, true); |
||||
CYBOZU_TEST_EQUAL(str, std::string("0x") + tbl[i].str); |
||||
} |
||||
} |
||||
|
||||
// CYBOZU_TEST_AUTO(toStr2) // QQQ
|
||||
// CYBOZU_TEST_AUTO(verifyStr) // QQQ
|
||||
|
||||
CYBOZU_TEST_AUTO(fromStr16) |
||||
{ |
||||
const struct { |
||||
const char *str; |
||||
uint64_t x[4]; |
||||
} tbl[] = { |
||||
{ "0", { 0, 0, 0, 0 } }, |
||||
{ "5", { 5, 0, 0, 0 } }, |
||||
{ "123", { 0x123, 0, 0, 0 } }, |
||||
{ "123456789012345679adbc", { uint64_t(0x789012345679adbcull), 0x123456, 0, 0 } }, |
||||
{ "ffffffff26f2fc170f69466a74defd8d", { uint64_t(0x0f69466a74defd8dull), uint64_t(0xffffffff26f2fc17ull), 0, 0 } }, |
||||
{ "100000000000000000000000000000033", { uint64_t(0x0000000000000033ull), 0, 1, 0 } }, |
||||
{ "11ee12312312940000000000000000000000000002342343", { uint64_t(0x0000000002342343ull), uint64_t(0x0000000000000000ull), uint64_t(0x11ee123123129400ull), 0 } }, |
||||
{ "1234567890abcdefABCDEF123456789aba32134723424242424", { uint64_t(0x2134723424242424ull), uint64_t(0xDEF123456789aba3ull), uint64_t(0x4567890abcdefABCull), 0x123 } }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const size_t xN = 4; |
||||
uint64_t x[xN]; |
||||
mcl::fp::fromStr16(x, xN, tbl[i].str, strlen(tbl[i].str)); |
||||
for (size_t j = 0; j < xN; j++) { |
||||
CYBOZU_TEST_EQUAL(x[j], tbl[i].x[j]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(compareArray) |
||||
{ |
||||
const struct { |
||||
uint32_t a[4]; |
||||
uint32_t b[4]; |
||||
size_t n; |
||||
int expect; |
||||
} tbl[] = { |
||||
{ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0 }, |
||||
{ { 1, 0, 0, 0 }, { 0, 0, 0, 0 }, 1, 1 }, |
||||
{ { 0, 0, 0, 0 }, { 1, 0, 0, 0 }, 1, -1 }, |
||||
{ { 1, 0, 0, 0 }, { 1, 0, 0, 0 }, 1, 0 }, |
||||
{ { 3, 1, 1, 0 }, { 2, 1, 1, 0 }, 4, 1 }, |
||||
{ { 9, 2, 1, 1 }, { 1, 3, 1, 1 }, 4, -1 }, |
||||
{ { 1, 7, 8, 4 }, { 1, 7, 8, 9 }, 3, 0 }, |
||||
{ { 1, 7, 8, 4 }, { 1, 7, 8, 9 }, 4, -1 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
int e = mcl::fp::compareArray(tbl[i].a, tbl[i].b, tbl[i].n); |
||||
CYBOZU_TEST_EQUAL(e, tbl[i].expect); |
||||
} |
||||
} |
||||
|
||||
struct Rand { |
||||
std::vector<uint32_t> v; |
||||
size_t pos; |
||||
int count; |
||||
void read(uint32_t *x, size_t n) |
||||
{ |
||||
if (v.size() < pos + n) throw cybozu::Exception("Rand:get:bad n") << v.size() << pos << n; |
||||
std::copy(v.begin() + pos, v.begin() + pos + n, x); |
||||
pos += n; |
||||
count++; |
||||
} |
||||
Rand(const uint32_t *x, size_t n) |
||||
: pos(0) |
||||
, count(0) |
||||
{ |
||||
for (size_t i = 0; i < n; i++) { |
||||
v.push_back(x[i]); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
CYBOZU_TEST_AUTO(getRandVal) |
||||
{ |
||||
const size_t rn = 8; |
||||
const struct { |
||||
uint32_t r[rn]; |
||||
uint32_t mod[2]; |
||||
size_t bitLen; |
||||
int count; |
||||
uint32_t expect[2]; |
||||
} tbl[] = { |
||||
{ { 1, 2, 3, 4, 5, 6, 7, 8 }, { 5, 6 }, 64, 1, { 1, 2 } }, |
||||
{ { 0xfffffffc, 0x7, 3, 4, 5, 6, 7, 8 }, { 0xfffffffe, 0x3 }, 34, 1, { 0xfffffffc, 0x3 } }, |
||||
{ { 0xfffffffc, 0x7, 3, 4, 5, 6, 7, 8 }, { 0xfffffffb, 0x3 }, 34, 2, { 3, 0 } }, |
||||
{ { 2, 3, 5, 7, 4, 3, 0, 3 }, { 1, 0x3 }, 34, 4, { 0, 3 } }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
Rand rg(tbl[i].r, rn); |
||||
uint32_t out[2]; |
||||
mcl::fp::getRandVal(out, rg, tbl[i].mod, tbl[i].bitLen); |
||||
CYBOZU_TEST_EQUAL(out[0], tbl[i].expect[0]); |
||||
CYBOZU_TEST_EQUAL(out[1], tbl[i].expect[1]); |
||||
CYBOZU_TEST_EQUAL(rg.count, tbl[i].count); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(shiftLeftOr) |
||||
{ |
||||
const struct { |
||||
uint32_t x[4]; |
||||
size_t n; |
||||
size_t shift; |
||||
uint32_t y; |
||||
uint32_t z[4]; |
||||
uint32_t ret; |
||||
} tbl[] = { |
||||
{ { 0x12345678, 0, 0, 0 }, 1, 0, 0, { 0x12345678, 0, 0, 0 }, 0 }, |
||||
{ { 0x12345678, 0, 0, 0 }, 1, 1, 0, { 0x2468acf0, 0, 0, 0 }, 0 }, |
||||
{ { 0xf2345678, 0, 0, 0 }, 1, 1, 5, { 0xe468acf5, 0, 0, 0 }, 1 }, |
||||
{ { 0x12345678, 0x9abcdef0, 0x11112222, 0xffccaaee }, 4, 19, 0x1234, { 0xb3c01234, 0xf78091a2, 0x1114d5e6, 0x57708889 }, 0x7fe65 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
uint32_t z[4]; |
||||
uint32_t ret = mcl::fp::shiftLeftOr(z, tbl[i].x, tbl[i].n, tbl[i].shift, tbl[i].y); |
||||
CYBOZU_TEST_EQUAL_ARRAY(z, tbl[i].z, tbl[i].n); |
||||
CYBOZU_TEST_EQUAL(ret, tbl[i].ret); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(shiftRight) |
||||
{ |
||||
const struct { |
||||
uint32_t x[4]; |
||||
size_t n; |
||||
size_t shift; |
||||
uint32_t z[4]; |
||||
} tbl[] = { |
||||
{ { 0x12345678, 0, 0, 0 }, 4, 0, { 0x12345678, 0, 0, 0 } }, |
||||
{ { 0x12345678, 0xaaaabbbb, 0xffeebbcc, 0xfeba9874 }, 4, 1, { 0x891a2b3c, 0x55555ddd, 0x7ff75de6, 0x7f5d4c3a } }, |
||||
{ { 0x12345678, 0xaaaabbbb, 0xffeebbcc, 0xfeba9874 }, 4, 18, { 0xaeeec48d, 0xaef32aaa, 0xa61d3ffb, 0x3fae } }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
uint32_t z[4]; |
||||
mcl::fp::shiftRight(z, tbl[i].x, tbl[i].n, tbl[i].shift); |
||||
CYBOZU_TEST_EQUAL_ARRAY(z, tbl[i].z, tbl[i].n); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(splitBitVec) |
||||
{ |
||||
uint32_t tbl[] = { 0x12345678, 0xaaaabbbb, 0xffeebbcc }; |
||||
typedef cybozu::BitVectorT<uint32_t> BitVec; |
||||
typedef std::vector<int> IntVec; |
||||
BitVec bv; |
||||
bv.append(tbl, sizeof(tbl) * 8); |
||||
for (size_t len = bv.size(); len > 0; len--) { |
||||
bv.resize(len); |
||||
for (size_t w = 1; w < 18; w++) { |
||||
IntVec iv; |
||||
size_t last = mcl::fp::splitBitVec(iv, bv, w); |
||||
size_t q = len / w; |
||||
size_t r = len % w; |
||||
if (r == 0) { |
||||
r = w; |
||||
} else { |
||||
q++; |
||||
} |
||||
CYBOZU_TEST_EQUAL(iv.size(), q); |
||||
BitVec bv2; |
||||
mcl::fp::concatBitVec(bv2, iv, w, last); |
||||
CYBOZU_TEST_ASSERT(bv == bv2); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@ |
||||
g++ -O3 -march=native base_test.cpp ../src/x86.s -m32 -I ~/32/include/ -I ../include/ -I ../../xbyak/ -I ../../cybozulib/include ~/32/lib/libgmp.a ~/32/lib/libgmpxx.a -I ~/32/lib -DNDEBUG |
@ -0,0 +1,809 @@ |
||||
#define PUT(x) std::cout << #x "=" << (x) << std::endl |
||||
#include <cybozu/test.hpp> |
||||
#include <cybozu/benchmark.hpp> |
||||
#include <time.h> |
||||
|
||||
#define USE_MONT_FP |
||||
#include <mcl/fp.hpp> |
||||
typedef mcl::FpT<> Zn; |
||||
typedef mcl::FpT<> MontFp3; |
||||
typedef mcl::FpT<> MontFp4; |
||||
typedef mcl::FpT<> MontFp6; |
||||
typedef mcl::FpT<> MontFp9; |
||||
|
||||
struct Montgomery { |
||||
typedef mcl::Gmp::BlockType BlockType; |
||||
mpz_class p_; |
||||
mpz_class R_; // (1 << (pn_ * 64)) % p
|
||||
mpz_class RR_; // (R * R) % p
|
||||
BlockType pp_; // p * pp = -1 mod M = 1 << 64
|
||||
size_t pn_; |
||||
Montgomery() {} |
||||
explicit Montgomery(const mpz_class& p) |
||||
{ |
||||
p_ = p; |
||||
pp_ = mcl::montgomery::getCoff(mcl::Gmp::getBlock(p, 0)); |
||||
pn_ = mcl::Gmp::getBlockSize(p); |
||||
R_ = 1; |
||||
R_ = (R_ << (pn_ * 64)) % p_; |
||||
RR_ = (R_ * R_) % p_; |
||||
} |
||||
|
||||
void toMont(mpz_class& x) const { mul(x, x, RR_); } |
||||
void fromMont(mpz_class& x) const { mul(x, x, 1); } |
||||
|
||||
void mul(mpz_class& z, const mpz_class& x, const mpz_class& y) const |
||||
{ |
||||
#if 0 |
||||
const size_t ySize = mcl::Gmp::getBlockSize(y); |
||||
mpz_class c = x * mcl::Gmp::getBlock(y, 0); |
||||
BlockType q = mcl::Gmp::getBlock(c, 0) * pp_; |
||||
c += p_ * q; |
||||
c >>= sizeof(BlockType) * 8; |
||||
for (size_t i = 1; i < pn_; i++) { |
||||
if (i < ySize) { |
||||
c += x * mcl::Gmp::getBlock(y, i); |
||||
} |
||||
BlockType q = mcl::Gmp::getBlock(c, 0) * pp_; |
||||
c += p_ * q; |
||||
c >>= sizeof(BlockType) * 8; |
||||
} |
||||
if (c >= p_) { |
||||
c -= p_; |
||||
} |
||||
z = c; |
||||
#else |
||||
z = x * y; |
||||
for (size_t i = 0; i < pn_; i++) { |
||||
BlockType q = mcl::Gmp::getBlock(z, 0) * pp_; |
||||
z += p_ * (mp_limb_t)q; |
||||
z >>= sizeof(BlockType) * 8; |
||||
} |
||||
if (z >= p_) { |
||||
z -= p_; |
||||
} |
||||
#endif |
||||
} |
||||
}; |
||||
|
||||
template<class T> |
||||
mpz_class toGmp(const T& x) |
||||
{ |
||||
std::string str = x.toStr(); |
||||
mpz_class t; |
||||
mcl::Gmp::fromStr(t, str); |
||||
return t; |
||||
} |
||||
|
||||
template<class T> |
||||
std::string toStr(const T& x) |
||||
{ |
||||
std::ostringstream os; |
||||
os << x; |
||||
return os.str(); |
||||
} |
||||
|
||||
template<class T, class U> |
||||
T castTo(const U& x) |
||||
{ |
||||
T t; |
||||
t.fromStr(toStr(x)); |
||||
return t; |
||||
} |
||||
|
||||
template<class T> |
||||
void putRaw(const T& x) |
||||
{ |
||||
const uint64_t *p = x.getInnerValue(); |
||||
for (size_t i = 0, n = T::BlockSize; i < n; i++) { |
||||
printf("%016llx", p[n - 1 - i]); |
||||
} |
||||
printf("\n"); |
||||
} |
||||
|
||||
template<size_t N> |
||||
void put(const uint64_t (&x)[N]) |
||||
{ |
||||
for (size_t i = 0; i < N; i++) { |
||||
printf("%016llx", x[N - 1 - i]); |
||||
} |
||||
printf("\n"); |
||||
} |
||||
|
||||
template<size_t N> |
||||
struct Test { |
||||
typedef mcl::FpT<> Fp; |
||||
mpz_class m; |
||||
void run(const char *p) |
||||
{ |
||||
Fp::setModulo(p); |
||||
m = p; |
||||
Zn::setModulo(p); |
||||
edge(); |
||||
cstr(); |
||||
toStr(); |
||||
fromStr(); |
||||
stream(); |
||||
conv(); |
||||
compare(); |
||||
modulo(); |
||||
ope(); |
||||
cvtInt(); |
||||
power(); |
||||
neg_power(); |
||||
power_Zn(); |
||||
setRaw(); |
||||
set64bit(); |
||||
getRaw(); |
||||
binaryExp(); |
||||
bench(); |
||||
} |
||||
void cstr() |
||||
{ |
||||
const struct { |
||||
const char *str; |
||||
int val; |
||||
} tbl[] = { |
||||
{ "0", 0 }, |
||||
{ "1", 1 }, |
||||
{ "123", 123 }, |
||||
{ "0x123", 0x123 }, |
||||
{ "0b10101", 21 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
// string cstr
|
||||
Fp x(tbl[i].str); |
||||
CYBOZU_TEST_EQUAL(x, tbl[i].val); |
||||
|
||||
// int cstr
|
||||
Fp y(tbl[i].val); |
||||
CYBOZU_TEST_EQUAL(y, x); |
||||
|
||||
// copy cstr
|
||||
Fp z(x); |
||||
CYBOZU_TEST_EQUAL(z, x); |
||||
|
||||
// assign int
|
||||
Fp w; |
||||
w = tbl[i].val; |
||||
CYBOZU_TEST_EQUAL(w, x); |
||||
|
||||
// assign self
|
||||
Fp u; |
||||
u = w; |
||||
CYBOZU_TEST_EQUAL(u, x); |
||||
|
||||
// conv
|
||||
std::ostringstream os; |
||||
os << tbl[i].val; |
||||
|
||||
std::string str; |
||||
x.toStr(str); |
||||
CYBOZU_TEST_EQUAL(str, os.str()); |
||||
} |
||||
const struct { |
||||
const char *str; |
||||
int val; |
||||
} tbl2[] = { |
||||
{ "-123", 123 }, |
||||
{ "-0x123", 0x123 }, |
||||
{ "-0b10101", 21 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl2); i++) { |
||||
Fp x(tbl2[i].str); |
||||
x = -x; |
||||
CYBOZU_TEST_EQUAL(x, tbl2[i].val); |
||||
} |
||||
} |
||||
void toStr() |
||||
{ |
||||
Fp x(0); |
||||
std::string str; |
||||
str = x.toStr(); |
||||
CYBOZU_TEST_EQUAL(str, "0"); |
||||
str = x.toStr(2, true); |
||||
CYBOZU_TEST_EQUAL(str, "0"); |
||||
str = x.toStr(2, false); |
||||
CYBOZU_TEST_EQUAL(str, "0"); |
||||
str = x.toStr(16, true); |
||||
CYBOZU_TEST_EQUAL(str, "0"); |
||||
str = x.toStr(16, false); |
||||
CYBOZU_TEST_EQUAL(str, "0"); |
||||
|
||||
x = 123; |
||||
str = x.toStr(); |
||||
CYBOZU_TEST_EQUAL(str, "123"); |
||||
str = x.toStr(2, true); |
||||
CYBOZU_TEST_EQUAL(str, "0b1111011"); |
||||
str = x.toStr(2, false); |
||||
CYBOZU_TEST_EQUAL(str, "1111011"); |
||||
str = x.toStr(16, true); |
||||
CYBOZU_TEST_EQUAL(str, "0x7b"); |
||||
str = x.toStr(16, false); |
||||
CYBOZU_TEST_EQUAL(str, "7b"); |
||||
|
||||
{ |
||||
std::ostringstream os; |
||||
os << x; |
||||
CYBOZU_TEST_EQUAL(os.str(), "123"); |
||||
} |
||||
{ |
||||
std::ostringstream os; |
||||
os << std::hex << std::showbase << x; |
||||
CYBOZU_TEST_EQUAL(os.str(), "0x7b"); |
||||
} |
||||
{ |
||||
std::ostringstream os; |
||||
os << std::hex << x; |
||||
CYBOZU_TEST_EQUAL(os.str(), "7b"); |
||||
} |
||||
} |
||||
|
||||
void fromStr() |
||||
{ |
||||
const struct { |
||||
const char *in; |
||||
int out; |
||||
int base; |
||||
} tbl[] = { |
||||
{ "100", 100, 0 }, // set base = 10 if base = 0
|
||||
{ "100", 4, 2 }, |
||||
{ "100", 256, 16 }, |
||||
{ "0b100", 4, 0 }, |
||||
{ "0b100", 4, 2 }, |
||||
{ "0x100", 256, 0 }, |
||||
{ "0x100", 256, 16 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
Fp x; |
||||
x.fromStr(tbl[i].in, tbl[i].base); |
||||
CYBOZU_TEST_EQUAL(x, tbl[i].out); |
||||
} |
||||
// conflict prefix with base
|
||||
Fp x; |
||||
CYBOZU_TEST_EXCEPTION(x.fromStr("0b100", 16), cybozu::Exception); |
||||
CYBOZU_TEST_EXCEPTION(x.fromStr("0x100", 2), cybozu::Exception); |
||||
} |
||||
|
||||
void stream() |
||||
{ |
||||
const struct { |
||||
const char *in; |
||||
int out10; |
||||
int out16; |
||||
} tbl[] = { |
||||
{ "100", 100, 256 }, // set base = 10 if base = 0
|
||||
{ "0x100", 256, 256 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
{ |
||||
std::istringstream is(tbl[i].in); |
||||
Fp x; |
||||
is >> x; |
||||
CYBOZU_TEST_EQUAL(x, tbl[i].out10); |
||||
} |
||||
{ |
||||
std::istringstream is(tbl[i].in); |
||||
Fp x; |
||||
is >> std::hex >> x; |
||||
CYBOZU_TEST_EQUAL(x, tbl[i].out16); |
||||
} |
||||
} |
||||
std::istringstream is("0b100"); |
||||
Fp x; |
||||
CYBOZU_TEST_EXCEPTION(is >> std::hex >> x, cybozu::Exception); |
||||
} |
||||
void edge() |
||||
{ |
||||
#if 0 |
||||
std::cout << std::hex; |
||||
/*
|
||||
real mont |
||||
0 0 |
||||
1 R^-1 |
||||
R 1 |
||||
-1 -R^-1 |
||||
-R -1 |
||||
*/ |
||||
mpz_class t = 1; |
||||
const mpz_class R = (t << (N * 64)) % m; |
||||
const mpz_class tbl[] = { |
||||
0, 1, R, m - 1, m - R |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const mpz_class& x = tbl[i]; |
||||
for (size_t j = i; j < CYBOZU_NUM_OF_ARRAY(tbl); j++) { |
||||
const mpz_class& y = tbl[j]; |
||||
mpz_class z = (x * y) % m; |
||||
Fp xx, yy; |
||||
Fp::toMont(xx, x); |
||||
Fp::toMont(yy, y); |
||||
Fp zz = xx * yy; |
||||
mpz_class t; |
||||
Fp::fromMont(t, zz); |
||||
CYBOZU_TEST_EQUAL(z, t); |
||||
} |
||||
} |
||||
std::cout << std::dec; |
||||
#endif |
||||
} |
||||
|
||||
void conv() |
||||
{ |
||||
const char *bin = "0b100100011010001010110011110001001000000010010001101000101011001111000100100000001001000110100010101100111100010010000"; |
||||
const char *hex = "0x123456789012345678901234567890"; |
||||
const char *dec = "94522879687365475552814062743484560"; |
||||
Fp b(bin); |
||||
Fp h(hex); |
||||
Fp d(dec); |
||||
CYBOZU_TEST_EQUAL(b, h); |
||||
CYBOZU_TEST_EQUAL(b, d); |
||||
|
||||
std::string str; |
||||
b.toStr(str, 2, true); |
||||
CYBOZU_TEST_EQUAL(str, bin); |
||||
b.toStr(str); |
||||
CYBOZU_TEST_EQUAL(str, dec); |
||||
b.toStr(str, 16, true); |
||||
CYBOZU_TEST_EQUAL(str, hex); |
||||
} |
||||
|
||||
void compare() |
||||
{ |
||||
const struct { |
||||
int lhs; |
||||
int rhs; |
||||
int cmp; |
||||
} tbl[] = { |
||||
{ 0, 0, 0 }, |
||||
{ 1, 0, 1 }, |
||||
{ 0, 1, -1 }, |
||||
{ -1, 0, 1 }, // m-1, 0
|
||||
{ 0, -1, -1 }, // 0, m-1
|
||||
{ 123, 456, -1 }, |
||||
{ 456, 123, 1 }, |
||||
{ 5, 5, 0 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const Fp x(tbl[i].lhs); |
||||
const Fp y(tbl[i].rhs); |
||||
const int cmp = tbl[i].cmp; |
||||
if (cmp == 0) { |
||||
CYBOZU_TEST_EQUAL(x, y); |
||||
} else { |
||||
CYBOZU_TEST_ASSERT(x != y); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void modulo() |
||||
{ |
||||
std::ostringstream ms; |
||||
ms << m; |
||||
|
||||
std::string str; |
||||
Fp::getModulo(str); |
||||
CYBOZU_TEST_EQUAL(str, ms.str()); |
||||
} |
||||
|
||||
void ope() |
||||
{ |
||||
const struct { |
||||
Zn x; |
||||
Zn y; |
||||
Zn add; // x + y
|
||||
Zn sub; // x - y
|
||||
Zn mul; // x * y
|
||||
Zn sqr; // x * x
|
||||
} tbl[] = { |
||||
{ 0, 1, 1, -1, 0, 0 }, |
||||
{ 9, 7, 16, 2, 63, 81 }, |
||||
{ 10, 13, 23, -3, 130, 100 }, |
||||
{ 2000, -1000, 1000, 3000, -2000000, 4000000 }, |
||||
{ -12345, -9999, -(12345 + 9999), - 12345 + 9999, 12345 * 9999, 12345 * 12345 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const Fp x(castTo<Fp>(tbl[i].x)); |
||||
const Fp y(castTo<Fp>(tbl[i].y)); |
||||
Fp z; |
||||
Fp::add(z, x, y); |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].add)); |
||||
Fp::sub(z, x, y); |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].sub)); |
||||
Fp::mul(z, x, y); |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].mul)); |
||||
|
||||
Fp r; |
||||
Fp::inv(r, y); |
||||
Zn rr = 1 / tbl[i].y; |
||||
CYBOZU_TEST_EQUAL(r, castTo<Fp>(rr)); |
||||
Fp::mul(z, z, r); |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].x)); |
||||
|
||||
z = x + y; |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].add)); |
||||
z = x - y; |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].sub)); |
||||
z = x * y; |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].mul)); |
||||
Fp::square(z, x); |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].sqr)); |
||||
|
||||
z = x / y; |
||||
z *= y; |
||||
CYBOZU_TEST_EQUAL(z, castTo<Fp>(tbl[i].x)); |
||||
} |
||||
} |
||||
void cvtInt() |
||||
{ |
||||
#if 0 |
||||
Fp x; |
||||
x = 12345; |
||||
uint64_t y = x.cvtInt(); |
||||
CYBOZU_TEST_EQUAL(y, 12345u); |
||||
x.fromStr("123456789012342342342342342"); |
||||
CYBOZU_TEST_EXCEPTION(x.cvtInt(), cybozu::Exception); |
||||
bool err = false; |
||||
CYBOZU_TEST_NO_EXCEPTION(x.cvtInt(&err)); |
||||
CYBOZU_TEST_ASSERT(err); |
||||
#endif |
||||
} |
||||
|
||||
void power() |
||||
{ |
||||
Fp x, y, z; |
||||
x = 12345; |
||||
z = 1; |
||||
for (int i = 0; i < 100; i++) { |
||||
Fp::power(y, x, i); |
||||
CYBOZU_TEST_EQUAL(y, z); |
||||
z *= x; |
||||
} |
||||
} |
||||
|
||||
void neg_power() |
||||
{ |
||||
Fp x, y, z; |
||||
x = 12345; |
||||
z = 1; |
||||
Fp rx = 1 / x; |
||||
for (int i = 0; i < 100; i++) { |
||||
Fp::power(y, x, -i); |
||||
CYBOZU_TEST_EQUAL(y, z); |
||||
z *= rx; |
||||
} |
||||
} |
||||
|
||||
void power_Zn() |
||||
{ |
||||
Fp x, y, z; |
||||
x = 12345; |
||||
z = 1; |
||||
for (int i = 0; i < 100; i++) { |
||||
Fp::power(y, x, Zn(i)); |
||||
CYBOZU_TEST_EQUAL(y, z); |
||||
z *= x; |
||||
} |
||||
} |
||||
|
||||
void setRaw() |
||||
{ |
||||
// QQQ
|
||||
#if 0 |
||||
char b1[] = { 0x56, 0x34, 0x12 }; |
||||
Fp x; |
||||
x.setRaw(b1, 3); |
||||
CYBOZU_TEST_EQUAL(x, 0x123456); |
||||
int b2[] = { 0x12, 0x34 }; |
||||
x.setRaw(b2, 2); |
||||
CYBOZU_TEST_EQUAL(x, Fp("0x3400000012")); |
||||
#endif |
||||
} |
||||
void binaryExp() |
||||
{ |
||||
puts("binaryExp"); |
||||
for (int i = 2; i < 7; i++) { |
||||
mpz_class g = m / i; |
||||
Fp x, y; |
||||
// Fp::toMont(x, g);
|
||||
x.fromGmp(g); |
||||
cybozu::BitVector bv; |
||||
x.appendToBitVec(bv); |
||||
uint64_t buf[N]; |
||||
mcl::Gmp::getRaw(buf, N, g); |
||||
CYBOZU_TEST_EQUAL(bv.getBlockSize(), N); |
||||
CYBOZU_TEST_EQUAL(bv.size(), Fp::getModBitLen()); |
||||
CYBOZU_TEST_EQUAL(bv.size(), Fp::getBitVecSize()); |
||||
const uint64_t *p = bv.getBlock(); |
||||
CYBOZU_TEST_EQUAL_ARRAY(p, buf, N); |
||||
} |
||||
const mpz_class yy("0x1255556666777788881111222233334444"); |
||||
if (yy > m) { |
||||
return; |
||||
} |
||||
Fp y; |
||||
// Fp::toMont(y, yy);
|
||||
y.fromGmp(yy); |
||||
uint64_t b1[N] = { uint64_t(0x1111222233334444ull), uint64_t(0x5555666677778888ull), 0x12 }; |
||||
Fp x; |
||||
cybozu::BitVector bv; |
||||
bv.append(b1, Fp::getModBitLen()); |
||||
x.fromBitVec(bv); |
||||
CYBOZU_TEST_EQUAL(x, y); |
||||
bv.clear(); |
||||
x.appendToBitVec(bv); |
||||
const uint64_t *b2 = bv.getBlock(); |
||||
CYBOZU_TEST_EQUAL_ARRAY(b1, b2, N); |
||||
} |
||||
|
||||
void set64bit() |
||||
{ |
||||
const struct { |
||||
const char *p; |
||||
uint64_t i; |
||||
} tbl[] = { |
||||
{ "0x1234567812345678", uint64_t(0x1234567812345678ull) }, |
||||
{ "0xaaaaaaaaaaaaaaaa", uint64_t(0xaaaaaaaaaaaaaaaaull) }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
Fp x(tbl[i].p); |
||||
Fp y(tbl[i].i); |
||||
CYBOZU_TEST_EQUAL(x, y); |
||||
} |
||||
} |
||||
|
||||
void getRaw() |
||||
{ |
||||
const struct { |
||||
const char *s; |
||||
uint32_t v[4]; |
||||
size_t vn; |
||||
} tbl[] = { |
||||
{ "0", { 0, 0, 0, 0 }, 1 }, |
||||
{ "1234", { 1234, 0, 0, 0 }, 1 }, |
||||
{ "0xaabbccdd12345678", { 0x12345678, 0xaabbccdd, 0, 0 }, 2 }, |
||||
{ "0x11112222333344445555666677778888", { 0x77778888, 0x55556666, 0x33334444, 0x11112222 }, 4 }, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
mpz_class x(tbl[i].s); |
||||
const size_t bufN = 8; |
||||
uint32_t buf[bufN]; |
||||
size_t n = mcl::Gmp::getRaw(buf, bufN, x); |
||||
CYBOZU_TEST_EQUAL(n, tbl[i].vn); |
||||
for (size_t j = 0; j < n; j++) { |
||||
CYBOZU_TEST_EQUAL(buf[j], tbl[i].v[j]); |
||||
} |
||||
} |
||||
} |
||||
void bench() |
||||
{ |
||||
Fp x("-123456789"); |
||||
Fp y("-0x7ffffffff"); |
||||
CYBOZU_BENCH("add", operator+, x, x); |
||||
CYBOZU_BENCH("sub", operator-, x, y); |
||||
CYBOZU_BENCH("mul", operator*, x, x); |
||||
CYBOZU_BENCH("sqr", Fp::square, x, x); |
||||
CYBOZU_BENCH("div", y += x; operator/, x, y); |
||||
} |
||||
}; |
||||
|
||||
void customTest(const char *pStr, const char *xStr, const char *yStr) |
||||
{ |
||||
#if 0 |
||||
{ |
||||
pStr = "0xfffffffffffffffffffffffffffffffffffffffeffffee37", |
||||
MontFp3::setModulo(pStr); |
||||
static uint64_t x[3] = { 1, 0, 0 }; |
||||
uint64_t z[3]; |
||||
std::cout<<std::hex; |
||||
MontFp3::inv(*(MontFp3*)z, *(const MontFp3*)x); |
||||
put(z); |
||||
exit(1); |
||||
} |
||||
#endif |
||||
#if 0 |
||||
std::cout << std::hex; |
||||
uint64_t x[9] = { 0xff7fffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1ff }; |
||||
uint64_t y[9] = { 0xff7fffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1ff }; |
||||
uint64_t z1[9], z2[9]; |
||||
MontFp9::setModulo(pStr); |
||||
MontFp9::fg_.mul_(z2, x, y); |
||||
put(z2); |
||||
{ |
||||
puts("C"); |
||||
mpz_class p(pStr); |
||||
Montgomery mont(p); |
||||
mpz_class xx, yy; |
||||
mcl::Gmp::setRaw(xx, x, CYBOZU_NUM_OF_ARRAY(x)); |
||||
mcl::Gmp::setRaw(yy, y, CYBOZU_NUM_OF_ARRAY(y)); |
||||
mpz_class z; |
||||
mont.mul(z, xx, yy); |
||||
std::cout << std::hex << z << std::endl; |
||||
} |
||||
exit(1); |
||||
#else |
||||
std::string rOrg, rC, rAsm; |
||||
Zn::setModulo(pStr); |
||||
Zn s(xStr), t(yStr); |
||||
s *= t; |
||||
rOrg = toStr(s); |
||||
{ |
||||
puts("C"); |
||||
mpz_class p(pStr); |
||||
Montgomery mont(p); |
||||
mpz_class x(xStr), y(yStr); |
||||
mont.toMont(x); |
||||
mont.toMont(y); |
||||
mpz_class z; |
||||
mont.mul(z, x, y); |
||||
mont.fromMont(z); |
||||
rC = toStr(z); |
||||
} |
||||
|
||||
puts("asm"); |
||||
MontFp9::setModulo(pStr); |
||||
MontFp9 x(xStr), y(yStr); |
||||
x *= y; |
||||
rAsm = toStr(x); |
||||
CYBOZU_TEST_EQUAL(rOrg, rC); |
||||
CYBOZU_TEST_EQUAL(rOrg, rAsm); |
||||
#endif |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(customTest) |
||||
{ |
||||
const struct { |
||||
const char *p; |
||||
const char *x; |
||||
const char *y; |
||||
} tbl[] = { |
||||
{ |
||||
"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", |
||||
// "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff",
|
||||
// "0xfffffffffffffffffffffffffffffffffffffffeffffee37",
|
||||
"0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", |
||||
"0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" |
||||
}, |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
customTest(tbl[i].p, tbl[i].x, tbl[i].y); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(test3) |
||||
{ |
||||
Test<3> test; |
||||
const char *tbl[] = { |
||||
"0x000000000000000100000000000000000000000000000033", // min prime
|
||||
"0x00000000fffffffffffffffffffffffffffffffeffffac73", |
||||
"0x0000000100000000000000000001b8fa16dfab9aca16b6b3", |
||||
"0x000000010000000000000000000000000000000000000007", |
||||
"0x30000000000000000000000000000000000000000000002b", |
||||
"0x70000000000000000000000000000000000000000000001f", |
||||
"0x800000000000000000000000000000000000000000000005", |
||||
"0xfffffffffffffffffffffffffffffffffffffffeffffee37", |
||||
"0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d", |
||||
"0xffffffffffffffffffffffffffffffffffffffffffffff13", // max prime
|
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
printf("prime=%s\n", tbl[i]); |
||||
test.run(tbl[i]); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(test4) |
||||
{ |
||||
Test<4> test; |
||||
const char *tbl[] = { |
||||
"0x0000000000000001000000000000000000000000000000000000000000000085", // min prime
|
||||
"0x2523648240000001ba344d80000000086121000000000013a700000000000013", |
||||
"0x7523648240000001ba344d80000000086121000000000013a700000000000017", |
||||
"0x800000000000000000000000000000000000000000000000000000000000005f", |
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43", // max prime
|
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
printf("prime=%s\n", tbl[i]); |
||||
test.run(tbl[i]); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(test6) |
||||
{ |
||||
Test<6> test; |
||||
const char *tbl[] = { |
||||
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff", |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
printf("prime=%s\n", tbl[i]); |
||||
test.run(tbl[i]); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(test9) |
||||
{ |
||||
Test<9> test; |
||||
const char *tbl[] = { |
||||
"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", |
||||
}; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
printf("prime=%s\n", tbl[i]); |
||||
test.run(tbl[i]); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(toStr16) |
||||
{ |
||||
const char *tbl[] = { |
||||
"0x0", |
||||
"0x5", |
||||
"0x123", |
||||
"0x123456789012345679adbc", |
||||
"0xffffffff26f2fc170f69466a74defd8d", |
||||
"0x100000000000000000000000000000033", |
||||
"0x11ee12312312940000000000000000000000000002342343" |
||||
}; |
||||
MontFp3::setModulo("0xffffffffffffffffffffffffffffffffffffffffffffff13"); |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
std::string str, str2; |
||||
MontFp3 x(tbl[i]); |
||||
x.toStr(str, 16); |
||||
mpz_class y(tbl[i]); |
||||
mcl::Gmp::toStr(str2, y, 16); |
||||
CYBOZU_TEST_EQUAL(str, str2); |
||||
} |
||||
} |
||||
|
||||
#if 0 |
||||
CYBOZU_TEST_AUTO(toStr16bench) |
||||
{ |
||||
const char *tbl[] = { |
||||
"0x0", |
||||
"0x5", |
||||
"0x123", |
||||
"0x123456789012345679adbc", |
||||
"0xffffffff26f2fc170f69466a74defd8d", |
||||
"0x100000000000000000000000000000033", |
||||
"0x11ee12312312940000000000000000000000000002342343" |
||||
}; |
||||
const int C = 500000; |
||||
MontFp3::setModulo("0xffffffffffffffffffffffffffffffffffffffffffffff13"); |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
std::string str, str2; |
||||
MontFp3 x(tbl[i]); |
||||
CYBOZU_BENCH_C("Mont:toStr", C, x.toStr, str, 16); |
||||
mpz_class y(tbl[i]); |
||||
CYBOZU_BENCH_C("Gmp:toStr ", C, mcl::Gmp::toStr, str2, y, 16); |
||||
str2.insert(0, "0x"); |
||||
CYBOZU_TEST_EQUAL(str, str2); |
||||
} |
||||
} |
||||
|
||||
CYBOZU_TEST_AUTO(fromStr16bench) |
||||
{ |
||||
const char *tbl[] = { |
||||
"0x0", |
||||
"0x5", |
||||
"0x123", |
||||
"0x123456789012345679adbc", |
||||
"0xffffffff26f2fc170f69466a74defd8d", |
||||
"0x100000000000000000000000000000033", |
||||
"0x11ee12312312940000000000000000000000000002342343" |
||||
}; |
||||
const int C = 500000; |
||||
MontFp3::setModulo("0xffffffffffffffffffffffffffffffffffffffffffffff13"); |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
std::string str = tbl[i]; |
||||
MontFp3 x; |
||||
CYBOZU_BENCH_C("Mont:fromStr", C, x.fromStr, str); |
||||
|
||||
mpz_class y; |
||||
str.erase(0, 2); |
||||
CYBOZU_BENCH_C("Gmp:fromStr ", C, mcl::Gmp::fromStr, y, str, 16); |
||||
x.toStr(str, 16); |
||||
std::string str2; |
||||
mcl::Gmp::toStr(str2, y, 16); |
||||
str2.insert(0, "0x"); |
||||
CYBOZU_TEST_EQUAL(str, str2); |
||||
} |
||||
} |
||||
#endif |
@ -0,0 +1,88 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup Label="ProjectConfigurations"> |
||||
<ProjectConfiguration Include="Debug|x64"> |
||||
<Configuration>Debug</Configuration> |
||||
<Platform>x64</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Release|x64"> |
||||
<Configuration>Release</Configuration> |
||||
<Platform>x64</Platform> |
||||
</ProjectConfiguration> |
||||
</ItemGroup> |
||||
<PropertyGroup Label="Globals"> |
||||
<ProjectGuid>{46B6E88E-739A-406B-9F68-BC46C5950FA3}</ProjectGuid> |
||||
<Keyword>Win32Proj</Keyword> |
||||
<RootNamespace>ec_test</RootNamespace> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
||||
<ConfigurationType>Application</ConfigurationType> |
||||
<UseDebugLibraries>true</UseDebugLibraries> |
||||
<PlatformToolset>v110</PlatformToolset> |
||||
<CharacterSet>MultiByte</CharacterSet> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
||||
<ConfigurationType>Application</ConfigurationType> |
||||
<UseDebugLibraries>false</UseDebugLibraries> |
||||
<PlatformToolset>v110</PlatformToolset> |
||||
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||
<CharacterSet>MultiByte</CharacterSet> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
||||
<ImportGroup Label="ExtensionSettings"> |
||||
</ImportGroup> |
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> |
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
<Import Project="$(SolutionDir)common.props" /> |
||||
<Import Project="$(SolutionDir)debug.props" /> |
||||
</ImportGroup> |
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> |
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
<Import Project="$(SolutionDir)common.props" /> |
||||
<Import Project="$(SolutionDir)release.props" /> |
||||
</ImportGroup> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
<LinkIncremental>true</LinkIncremental> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
<LinkIncremental>false</LinkIncremental> |
||||
</PropertyGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
<ClCompile> |
||||
<PrecompiledHeader> |
||||
</PrecompiledHeader> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<Optimization>Disabled</Optimization> |
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Console</SubSystem> |
||||
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
<ClCompile> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<PrecompiledHeader> |
||||
</PrecompiledHeader> |
||||
<Optimization>MaxSpeed</Optimization> |
||||
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Console</SubSystem> |
||||
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
<OptimizeReferences>true</OptimizeReferences> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup> |
||||
<ClCompile Include="$(SolutionDir)test\ec_test.cpp" /> |
||||
</ItemGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
||||
<ImportGroup Label="ExtensionTargets"> |
||||
</ImportGroup> |
||||
</Project> |
@ -0,0 +1,91 @@ |
||||
þ½Ž¿<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup Label="ProjectConfigurations"> |
||||
<ProjectConfiguration Include="Debug|x64"> |
||||
<Configuration>Debug</Configuration> |
||||
<Platform>x64</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Release|x64"> |
||||
<Configuration>Release</Configuration> |
||||
<Platform>x64</Platform> |
||||
</ProjectConfiguration> |
||||
</ItemGroup> |
||||
<PropertyGroup Label="Globals"> |
||||
<ProjectGuid>{51266DE6-B57B-4AE3-B85C-282F170E1728}</ProjectGuid> |
||||
<Keyword>Win32Proj</Keyword> |
||||
<RootNamespace>fp_test</RootNamespace> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
||||
<ConfigurationType>Application</ConfigurationType> |
||||
<UseDebugLibraries>true</UseDebugLibraries> |
||||
<PlatformToolset>v110</PlatformToolset> |
||||
<CharacterSet>MultiByte</CharacterSet> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
||||
<ConfigurationType>Application</ConfigurationType> |
||||
<UseDebugLibraries>false</UseDebugLibraries> |
||||
<PlatformToolset>v110</PlatformToolset> |
||||
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||
<CharacterSet>MultiByte</CharacterSet> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
||||
<ImportGroup Label="ExtensionSettings"> |
||||
</ImportGroup> |
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> |
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
<Import Project="$(SolutionDir)common.props" /> |
||||
<Import Project="$(SolutionDir)debug.props" /> |
||||
</ImportGroup> |
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> |
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
<Import Project="$(SolutionDir)common.props" /> |
||||
<Import Project="$(SolutionDir)release.props" /> |
||||
</ImportGroup> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
<LinkIncremental>true</LinkIncremental> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
<LinkIncremental>false</LinkIncremental> |
||||
</PropertyGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
<ClCompile> |
||||
<PrecompiledHeader> |
||||
</PrecompiledHeader> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<Optimization>Disabled</Optimization> |
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
<AdditionalIncludeDirectories>$(SolutionDir)../xbyak/;$(SolutionDir)../cybozulib/include;$(SolutionDir)../cybozulib_ext/mpir/include;$(SolutionDir)include</AdditionalIncludeDirectories> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Console</SubSystem> |
||||
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
<ClCompile> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<PrecompiledHeader> |
||||
</PrecompiledHeader> |
||||
<Optimization>MaxSpeed</Optimization> |
||||
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
<AdditionalIncludeDirectories>$(SolutionDir)../xbyak/;$(SolutionDir)../cybozulib/include;$(SolutionDir)../cybozulib_ext/mpir/include;$(SolutionDir)include</AdditionalIncludeDirectories> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Console</SubSystem> |
||||
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
<OptimizeReferences>true</OptimizeReferences> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup> |
||||
<ClCompile Include="$(SolutionDir)test\\fp_test.cpp" /> |
||||
</ItemGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
||||
<ImportGroup Label="ExtensionTargets"> |
||||
</ImportGroup> |
||||
</Project> |
@ -0,0 +1,21 @@ |
||||
#include <mcl/gmp_util.hpp> |
||||
#include <cybozu/test.hpp> |
||||
#include <iostream> |
||||
|
||||
CYBOZU_TEST_AUTO(sqrt) |
||||
{ |
||||
const int tbl[] = { 3, 5, 7, 11, 13, 17, 19, 257, 997, 1031 }; |
||||
mcl::SquareRoot sq; |
||||
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { |
||||
const mpz_class p = tbl[i]; |
||||
sq.set(p); |
||||
for (mpz_class a = 1; a < p; a++) { |
||||
mpz_class x; |
||||
if (sq.get(x, a)) { |
||||
mpz_class y; |
||||
y = (x * x) % p; |
||||
CYBOZU_TEST_EQUAL(a, y); |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue