You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
573 lines
11 KiB
573 lines
11 KiB
//#define MCL_EC_USE_AFFINE
|
|
#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>
|
|
#include <mcl/ec.hpp>
|
|
#include <mcl/ecparam.hpp>
|
|
#include <time.h>
|
|
#include <math.h>
|
|
|
|
typedef mcl::FpT<> Fp;
|
|
struct tagZn;
|
|
typedef mcl::FpT<tagZn> Zn;
|
|
typedef mcl::EcT<Fp> Ec;
|
|
|
|
CYBOZU_TEST_AUTO(sizeof)
|
|
{
|
|
CYBOZU_TEST_EQUAL(sizeof(Fp), sizeof(mcl::fp::Unit) * Fp::maxSize);
|
|
#ifdef MCL_EC_USE_AFFINE
|
|
CYBOZU_TEST_EQUAL(sizeof(Ec), sizeof(Fp) * 2 + sizeof(mcl::fp::Unit));
|
|
#else
|
|
CYBOZU_TEST_EQUAL(sizeof(Ec), sizeof(Fp) * 3);
|
|
#endif
|
|
}
|
|
|
|
struct Test {
|
|
const mcl::EcParam& para;
|
|
Test(const mcl::EcParam& para, mcl::fp::Mode fpMode, mcl::ec::Mode ecMode)
|
|
: para(para)
|
|
{
|
|
printf("fpMode=%s\n", mcl::fp::ModeToStr(fpMode));
|
|
Fp::init(para.p, fpMode);
|
|
Zn::init(para.n, fpMode);
|
|
Ec::init(para.a, para.b, ecMode);
|
|
}
|
|
void cstr() const
|
|
{
|
|
Ec O;
|
|
O.clear();
|
|
CYBOZU_TEST_ASSERT(O.isZero());
|
|
CYBOZU_TEST_ASSERT(O.isValid());
|
|
Ec P;
|
|
P.clear();
|
|
Ec::neg(P, O);
|
|
CYBOZU_TEST_EQUAL(P, O);
|
|
}
|
|
void pow2(Ec& Q, const Ec& P, int n) const
|
|
{
|
|
Q = P;
|
|
for (int i = 0; i < n; i++) {
|
|
Q += Q;
|
|
}
|
|
}
|
|
void pow2test(const Ec& P, int n) const
|
|
{
|
|
Ec Q, R;
|
|
pow2(Q, P, n);
|
|
Q -= P; // Q = (2^n - 1)P
|
|
Fp x = 1;
|
|
for (int i = 0; i < n; i++) {
|
|
x += x;
|
|
}
|
|
x -= 1; // x = 2^n - 1
|
|
Ec::mul(R, P, x);
|
|
CYBOZU_TEST_EQUAL(Q, R);
|
|
Q = P;
|
|
Ec::mul(Q, Q, x);
|
|
CYBOZU_TEST_EQUAL(Q, R);
|
|
}
|
|
void ope() const
|
|
{
|
|
Fp x(para.gx);
|
|
Fp y(para.gy);
|
|
Zn n = 0;
|
|
CYBOZU_TEST_NO_EXCEPTION(Ec(x, y));
|
|
CYBOZU_TEST_EXCEPTION(Ec(x, y + 1), cybozu::Exception);
|
|
Ec P(x, y), Q, R, O;
|
|
O.clear();
|
|
CYBOZU_TEST_ASSERT(P.isNormalized());
|
|
{
|
|
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());
|
|
CYBOZU_TEST_ASSERT(R.isNormalized());
|
|
CYBOZU_TEST_ASSERT(R.isValid());
|
|
|
|
R = P + O;
|
|
CYBOZU_TEST_EQUAL(R, P);
|
|
R = O + P;
|
|
CYBOZU_TEST_EQUAL(R, P);
|
|
}
|
|
|
|
{
|
|
Ec::dbl(R, P);
|
|
#ifndef MCL_EC_USE_AFFINE
|
|
CYBOZU_TEST_ASSERT(!R.isNormalized());
|
|
#endif
|
|
CYBOZU_TEST_ASSERT(R.isValid());
|
|
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::mul(R, P, 2);
|
|
CYBOZU_TEST_EQUAL(R, R2);
|
|
Ec R4L = R3L + R2;
|
|
Ec R4R = R2 + R3L;
|
|
CYBOZU_TEST_EQUAL(R4L, R4R);
|
|
Ec::mul(R, P, 5);
|
|
CYBOZU_TEST_EQUAL(R, R4L);
|
|
}
|
|
{
|
|
R = P;
|
|
for (int i = 0; i < 10; i++) {
|
|
R += P;
|
|
}
|
|
Ec R2;
|
|
Ec::mul(R2, P, 11);
|
|
CYBOZU_TEST_EQUAL(R, R2);
|
|
}
|
|
Ec::mul(R, P, n - 1);
|
|
CYBOZU_TEST_EQUAL(R, -P);
|
|
R += P; // Ec::mul(R, P, n);
|
|
CYBOZU_TEST_ASSERT(R.isZero());
|
|
{
|
|
const int tbl[] = { 1, 2, 63, 64, 65, 127, 128, 129 };
|
|
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
|
|
pow2test(P, tbl[i]);
|
|
}
|
|
}
|
|
{
|
|
Ec::mul(Q, P, 0);
|
|
CYBOZU_TEST_ASSERT(Q.isZero());
|
|
Q = P;
|
|
CYBOZU_TEST_ASSERT(!Q.isZero());
|
|
Ec::mul(Q, Q, 0);
|
|
CYBOZU_TEST_ASSERT(Q.isZero());
|
|
Ec::mul(Q, P, 1);
|
|
CYBOZU_TEST_EQUAL(P, Q);
|
|
}
|
|
{
|
|
Ec R2;
|
|
P += P;
|
|
Q += P;
|
|
CYBOZU_TEST_ASSERT(!P.z.isOne());
|
|
CYBOZU_TEST_ASSERT(!Q.z.isOne());
|
|
Ec::add(R2, P, Q);
|
|
|
|
P.normalize();
|
|
CYBOZU_TEST_ASSERT(P.z.isOne());
|
|
CYBOZU_TEST_ASSERT(!Q.z.isOne());
|
|
// affine + generic
|
|
Ec::add(R, P, Q);
|
|
CYBOZU_TEST_EQUAL(R, R2);
|
|
// generic + affine
|
|
Ec::add(R, Q, P);
|
|
CYBOZU_TEST_EQUAL(R, R2);
|
|
|
|
Q.normalize();
|
|
CYBOZU_TEST_ASSERT(P.z.isOne());
|
|
CYBOZU_TEST_ASSERT(Q.z.isOne());
|
|
// affine + affine
|
|
Ec::add(R, P, Q);
|
|
CYBOZU_TEST_EQUAL(R, R2);
|
|
|
|
P += P;
|
|
CYBOZU_TEST_ASSERT(!P.z.isOne());
|
|
// generic
|
|
Ec::dbl(R2, P);
|
|
|
|
P.normalize();
|
|
CYBOZU_TEST_ASSERT(P.z.isOne());
|
|
// affine
|
|
Ec::dbl(R, P);
|
|
CYBOZU_TEST_EQUAL(R, R2);
|
|
}
|
|
}
|
|
|
|
void mul() const
|
|
{
|
|
Fp x(para.gx);
|
|
Fp y(para.gy);
|
|
Ec P(x, y);
|
|
Ec Q;
|
|
Ec R;
|
|
R.clear();
|
|
for (int i = 0; i < 100; i++) {
|
|
Ec::mul(Q, P, i);
|
|
CYBOZU_TEST_EQUAL(Q, R);
|
|
R += P;
|
|
}
|
|
}
|
|
|
|
void neg_mul() const
|
|
{
|
|
Fp x(para.gx);
|
|
Fp y(para.gy);
|
|
Ec P(x, y);
|
|
Ec Q;
|
|
Ec R;
|
|
R.clear();
|
|
for (int i = 0; i < 100; i++) {
|
|
Ec::mul(Q, P, -i);
|
|
CYBOZU_TEST_EQUAL(Q, R);
|
|
R -= P;
|
|
}
|
|
}
|
|
void squareRoot() const
|
|
{
|
|
Fp x(para.gx);
|
|
Fp y(para.gy);
|
|
bool odd = y.isOdd();
|
|
Fp yy;
|
|
bool b = Ec::getYfromX(yy, x, odd);
|
|
CYBOZU_TEST_ASSERT(b);
|
|
CYBOZU_TEST_EQUAL(yy, y);
|
|
Fp::neg(y, y);
|
|
odd = y.isOdd();
|
|
yy.clear();
|
|
b = Ec::getYfromX(yy, x, odd);
|
|
CYBOZU_TEST_ASSERT(b);
|
|
CYBOZU_TEST_EQUAL(yy, y);
|
|
}
|
|
void mul_fp() const
|
|
{
|
|
Fp x(para.gx);
|
|
Fp y(para.gy);
|
|
Ec P(x, y);
|
|
Ec Q;
|
|
Ec R;
|
|
R.clear();
|
|
for (int i = 0; i < 100; i++) {
|
|
Ec::mul(Q, P, Zn(i));
|
|
CYBOZU_TEST_EQUAL(Q, R);
|
|
R += P;
|
|
}
|
|
}
|
|
void str() const
|
|
{
|
|
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);
|
|
}
|
|
{
|
|
Q.clear();
|
|
CYBOZU_TEST_EQUAL(Q.getStr(), "0");
|
|
}
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int j = 0; j < 2; j++) {
|
|
int base = i == 0 ? 10 : 16;
|
|
bool withPrefix = j == 0;
|
|
int ioMode = base | (withPrefix ? mcl::IoPrefix : 0);
|
|
std::string expected = "1 " + x.getStr(ioMode) + " " + y.getStr(ioMode);
|
|
CYBOZU_TEST_EQUAL(P.getStr(ioMode), expected);
|
|
std::ostringstream os;
|
|
if (base == 16) {
|
|
os << std::hex;
|
|
}
|
|
if (withPrefix) {
|
|
os << std::showbase;
|
|
}
|
|
os << P;
|
|
CYBOZU_TEST_EQUAL(os.str(), expected);
|
|
}
|
|
}
|
|
{
|
|
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);
|
|
}
|
|
CYBOZU_TEST_EXCEPTION(P.setStr("1 3 5"), cybozu::Exception);
|
|
// 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);
|
|
}
|
|
// IoSerialize, IoSerializeHexStr
|
|
const size_t adj = Ec::isMSBserialize() ? 0 : 1;
|
|
P.set(x, y);
|
|
{
|
|
std::string s = P.getStr(mcl::IoSerialize);
|
|
CYBOZU_TEST_EQUAL(s.size(), Fp::getByteSize() + adj);
|
|
Q.setStr(s, mcl::IoSerialize);
|
|
CYBOZU_TEST_EQUAL(P, Q);
|
|
}
|
|
{
|
|
std::string s = P.getStr(mcl::IoSerializeHexStr);
|
|
CYBOZU_TEST_EQUAL(s.size(), (Fp::getByteSize() + adj) * 2);
|
|
Q.setStr(s, mcl::IoSerializeHexStr);
|
|
CYBOZU_TEST_EQUAL(P, Q);
|
|
}
|
|
P = -P;
|
|
{
|
|
std::string s = P.getStr(mcl::IoSerialize);
|
|
CYBOZU_TEST_EQUAL(s.size(), Fp::getByteSize() + adj);
|
|
Q.setStr(s, mcl::IoSerialize);
|
|
CYBOZU_TEST_EQUAL(P, Q);
|
|
}
|
|
{
|
|
std::string s = P.getStr(mcl::IoSerializeHexStr);
|
|
CYBOZU_TEST_EQUAL(s.size(), (Fp::getByteSize() + adj) * 2);
|
|
Q.setStr(s, mcl::IoSerializeHexStr);
|
|
CYBOZU_TEST_EQUAL(P, Q);
|
|
}
|
|
P.clear();
|
|
{
|
|
std::string s = P.getStr(mcl::IoSerialize);
|
|
CYBOZU_TEST_EQUAL(s.size(), Fp::getByteSize() + adj);
|
|
CYBOZU_TEST_ASSERT(mcl::fp::isZeroArray(s.c_str(), s.size()));
|
|
Q.setStr(s, mcl::IoSerialize);
|
|
CYBOZU_TEST_EQUAL(P, Q);
|
|
}
|
|
{
|
|
std::string s = P.getStr(mcl::IoSerializeHexStr);
|
|
CYBOZU_TEST_EQUAL(s.size(), (Fp::getByteSize() + adj) * 2);
|
|
for (size_t i = 0; i < s.size(); i++) {
|
|
CYBOZU_TEST_EQUAL(s[i], '0');
|
|
}
|
|
Q.setStr(s, mcl::IoSerializeHexStr);
|
|
CYBOZU_TEST_EQUAL(P, Q);
|
|
}
|
|
}
|
|
void ioMode() const
|
|
{
|
|
const Fp x(para.gx);
|
|
const Fp y(para.gy);
|
|
Ec P(x, y);
|
|
const mcl::IoMode tbl[] = {
|
|
mcl::IoBin,
|
|
mcl::IoDec,
|
|
mcl::IoHex,
|
|
mcl::IoArray,
|
|
mcl::IoArrayRaw,
|
|
};
|
|
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
|
|
Fp::setIoMode(tbl[i]);
|
|
{
|
|
std::stringstream ss;
|
|
ss << P;
|
|
Ec Q;
|
|
ss >> Q;
|
|
CYBOZU_TEST_EQUAL(P, Q);
|
|
}
|
|
{
|
|
std::stringstream ss;
|
|
Ec Q;
|
|
Q.clear();
|
|
ss << Q;
|
|
Ec R;
|
|
ss >> R;
|
|
CYBOZU_TEST_EQUAL(Q, R);
|
|
}
|
|
}
|
|
Fp::setIoMode(mcl::IoAuto);
|
|
}
|
|
void mulCT() const
|
|
{
|
|
Fp x(para.gx);
|
|
Fp y(para.gy);
|
|
Ec P(x, y), Q1, Q2;
|
|
for (int i = 0; i < 100; i++) {
|
|
Zn r = i;
|
|
Ec::mul(Q1, P, r);
|
|
Ec::mulCT(Q2, P, r);
|
|
CYBOZU_TEST_EQUAL(Q1, Q2);
|
|
}
|
|
}
|
|
void compare() const
|
|
{
|
|
Fp x(para.gx);
|
|
Fp y(para.gy);
|
|
Ec P1(x, y);
|
|
Ec P2(x, -y);
|
|
int c = Ec::compare(P1, P2);
|
|
int cx = Fp::compare(y, -y);
|
|
CYBOZU_TEST_EQUAL(c, cx);
|
|
c = Ec::compare(P2, P1);
|
|
cx = Fp::compare(-y, y);
|
|
CYBOZU_TEST_EQUAL(c, cx);
|
|
CYBOZU_TEST_EQUAL(Ec::compare(P1, P1), 0);
|
|
bool b1, b2;
|
|
b1 = P1 <= P2;
|
|
b2 = y <= -y;
|
|
CYBOZU_TEST_EQUAL(b1, b2);
|
|
b1 = P1 < P2;
|
|
b2 = y < -y;
|
|
CYBOZU_TEST_EQUAL(b1, b2);
|
|
CYBOZU_TEST_ASSERT(!(P1 < P1));
|
|
CYBOZU_TEST_ASSERT((P1 <= P1));
|
|
}
|
|
|
|
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);
|
|
}
|
|
/*
|
|
Affine : sandy-bridge
|
|
add 3.17usec
|
|
sub 2.43usec
|
|
dbl 3.32usec
|
|
mul 905.00usec
|
|
Jacobi
|
|
add 2.34usec
|
|
sub 2.65usec
|
|
dbl 1.56usec
|
|
mul 499.00usec
|
|
*/
|
|
void run() const
|
|
{
|
|
cstr();
|
|
ope();
|
|
mul();
|
|
neg_mul();
|
|
mul_fp();
|
|
squareRoot();
|
|
str();
|
|
ioMode();
|
|
mulCT();
|
|
compare();
|
|
}
|
|
private:
|
|
Test(const Test&);
|
|
void operator=(const Test&);
|
|
};
|
|
|
|
void test_sub_sub(const mcl::EcParam& para, mcl::fp::Mode fpMode)
|
|
{
|
|
puts("Proj");
|
|
Test(para, fpMode, mcl::ec::Proj).run();
|
|
puts("Jacobi");
|
|
Test(para, fpMode, mcl::ec::Jacobi).run();
|
|
}
|
|
|
|
void test_sub(const mcl::EcParam *para, size_t paraNum)
|
|
{
|
|
for (size_t i = 0; i < paraNum; i++) {
|
|
puts(para[i].name);
|
|
test_sub_sub(para[i], mcl::fp::FP_GMP);
|
|
#ifdef MCL_USE_LLVM
|
|
test_sub_sub(para[i], mcl::fp::FP_LLVM);
|
|
test_sub_sub(para[i], mcl::fp::FP_LLVM_MONT);
|
|
#endif
|
|
#ifdef MCL_USE_XBYAK
|
|
test_sub_sub(para[i], mcl::fp::FP_XBYAK);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int g_partial = -1;
|
|
|
|
CYBOZU_TEST_AUTO(all)
|
|
{
|
|
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(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(para4, CYBOZU_NUM_OF_ARRAY(para4));
|
|
}
|
|
|
|
#if MCL_MAX_BIT_SIZE >= 384
|
|
if (g_partial & (1 << 6)) {
|
|
const struct mcl::EcParam para6[] = {
|
|
// mcl::ecparam::secp384r1,
|
|
mcl::ecparam::NIST_P384,
|
|
};
|
|
test_sub(para6, CYBOZU_NUM_OF_ARRAY(para6));
|
|
}
|
|
#endif
|
|
|
|
#if MCL_MAX_BIT_SIZE >= 521
|
|
if (g_partial & (1 << 9)) {
|
|
const struct mcl::EcParam para9[] = {
|
|
// mcl::ecparam::secp521r1,
|
|
mcl::ecparam::NIST_P521,
|
|
};
|
|
test_sub(para9, CYBOZU_NUM_OF_ARRAY(para9));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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);
|
|
}
|
|
|