aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/dexon-foundation/mcl/test/vint_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/dexon-foundation/mcl/test/vint_test.cpp')
-rw-r--r--vendor/github.com/dexon-foundation/mcl/test/vint_test.cpp1353
1 files changed, 1353 insertions, 0 deletions
diff --git a/vendor/github.com/dexon-foundation/mcl/test/vint_test.cpp b/vendor/github.com/dexon-foundation/mcl/test/vint_test.cpp
new file mode 100644
index 000000000..15e14266a
--- /dev/null
+++ b/vendor/github.com/dexon-foundation/mcl/test/vint_test.cpp
@@ -0,0 +1,1353 @@
+#include <stdio.h>
+#include <mcl/vint.hpp>
+#include <iostream>
+#include <sstream>
+#include <set>
+#include <cybozu/benchmark.hpp>
+#include <cybozu/test.hpp>
+#include <cybozu/xorshift.hpp>
+#ifndef DONT_USE_GMP_IN_TEST
+#include <gmpxx.h>
+#endif
+
+#define PUT(x) std::cout << #x "=" << x << std::endl;
+
+#if defined(__EMSCRIPTEN__) && !defined(MCL_AVOID_EXCEPTION_TEST)
+ #define MCL_AVOID_EXCEPTION_TEST
+#endif
+
+using namespace mcl;
+
+struct V {
+ int n;
+ unsigned int p[16];
+};
+
+CYBOZU_TEST_AUTO(addSub)
+{
+ static const struct {
+ V a;
+ V b;
+ V c;
+ } tbl[] = {
+ {
+ { 1, { 123, } },
+ { 1, { 456, } },
+ { 1, { 579, } },
+ },
+ {
+ { 1, { 0xffffffff, } },
+ { 1, { 3, } },
+ { 2, { 2, 1 } },
+ },
+ {
+ { 3, { 0xffffffff, 1, 0xffffffff } },
+ { 2, { 1, 0xfffffffe, } },
+ { 4, { 0, 0, 0, 1 } },
+ },
+ {
+ { 3, { 0xffffffff, 5, 0xffffffff } },
+ { 2, { 1, 0xfffffffe, } },
+ { 4, { 0, 4, 0, 1 } },
+ },
+ {
+ { 3, { 0xffffffff, 5, 0xffffffff } },
+ { 1, { 1, } },
+ { 3, { 0, 6, 0xffffffff } },
+ },
+ {
+ { 3, { 1, 0xffffffff, 1 } },
+ { 3, { 0xffffffff, 0, 1 } },
+ { 3, { 0, 0, 3 } },
+ },
+ {
+ { 1, { 1 } },
+ { 3, { 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 4, { 0, 0, 0, 1 } },
+ },
+ {
+ { 1, { 0xffffffff } },
+ { 1, { 0xffffffff } },
+ { 2, { 0xfffffffe, 1 } },
+ },
+ {
+ { 2, { 0xffffffff, 0xffffffff } },
+ { 2, { 0xffffffff, 0xffffffff } },
+ { 3, { 0xfffffffe, 0xffffffff, 1 } },
+ },
+ {
+ { 3, { 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 3, { 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 4, { 0xfffffffe, 0xffffffff, 0xffffffff, 1 } },
+ },
+ {
+ { 4, { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 4, { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 5, { 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 1 } },
+ },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ Vint x, y, z, t;
+ x.setArray(tbl[i].a.p, tbl[i].a.n);
+ y.setArray(tbl[i].b.p, tbl[i].b.n);
+ z.setArray(tbl[i].c.p, tbl[i].c.n);
+ Vint::add(t, x, y);
+ CYBOZU_TEST_EQUAL(t, z);
+
+ Vint::add(t, y, x);
+ CYBOZU_TEST_EQUAL(t, z);
+
+ Vint::sub(t, z, x);
+ CYBOZU_TEST_EQUAL(t, y);
+ }
+ {
+ const uint32_t in[] = { 0xffffffff, 0xffffffff };
+ const uint32_t out[] = { 0xfffffffe, 0xffffffff, 1 };
+ Vint x, y;
+ x.setArray(in, 2);
+ y.setArray(out, 3);
+ Vint::add(x, x, x);
+ CYBOZU_TEST_EQUAL(x, y);
+ Vint::sub(x, x, x);
+ y.clear();
+ CYBOZU_TEST_EQUAL(x, y);
+ }
+ {
+ const uint32_t t0[] = {1, 2};
+ const uint32_t t1[] = {3, 4, 5};
+ const uint32_t t2[] = {4, 6, 5};
+ Vint x, y, z;
+ z.setArray(t2, 3);
+
+ x.setArray(t0, 2);
+ y.setArray(t1, 3);
+ Vint::add(x, x, y);
+ CYBOZU_TEST_EQUAL(x, z);
+
+ x.setArray(t0, 2);
+ y.setArray(t1, 3);
+ Vint::add(x, y, x);
+ CYBOZU_TEST_EQUAL(x, z);
+
+ x.setArray(t0, 2);
+ y.setArray(t1, 3);
+ Vint::add(y, x, y);
+ CYBOZU_TEST_EQUAL(y, z);
+
+ x.setArray(t0, 2);
+ y.setArray(t1, 3);
+ Vint::add(y, y, x);
+ CYBOZU_TEST_EQUAL(y, z);
+ }
+}
+
+CYBOZU_TEST_AUTO(mul1)
+{
+ static const struct {
+ V a;
+ int b;
+ V c;
+ } tbl[] = {
+ {
+ { 1, { 12, } },
+ 5,
+ { 1, { 60, } },
+ },
+ {
+ { 1, { 1234567, } },
+ 1,
+ { 1, { 1234567, } },
+ },
+ {
+ { 1, { 1234567, } },
+ 89012345,
+ { 2, { 0x27F6EDCF, 0x63F2, } },
+ },
+ {
+ { 3, { 0xffffffff, 0xffffffff, 0xffffffff, } },
+ 0x7fffffff,
+ { 4, { 0x80000001, 0xffffffff, 0xffffffff, 0x7ffffffe } },
+ },
+ {
+ { 3, { 0xffffffff, 0xffffffff, 0xffffffff, } },
+ 1,
+ { 3, { 0xffffffff, 0xffffffff, 0xffffffff, } },
+ },
+ {
+ { 2, { 0xffffffff, 1 } },
+ 0x7fffffff,
+ { 2, { 0x80000001, 0xfffffffd } },
+ },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ Vint x, z, t;
+ int y;
+ x.setArray(tbl[i].a.p, tbl[i].a.n);
+ y = tbl[i].b;
+ z.setArray(tbl[i].c.p, tbl[i].c.n);
+ Vint::mul(t, x, y);
+ CYBOZU_TEST_EQUAL(t, z);
+
+ Vint::mul(x, x, y);
+ CYBOZU_TEST_EQUAL(x, z);
+ }
+}
+
+CYBOZU_TEST_AUTO(mul2)
+{
+ static const struct {
+ V a;
+ V b;
+ V c;
+ } tbl[] = {
+ {
+ { 1, { 12, } },
+ { 1, { 5, } },
+ { 1, { 60, } },
+ },
+ {
+ { 1, { 1234567, } },
+ { 1, { 89012345, } },
+ { 2, { 0x27F6EDCF, 0x63F2, } },
+ },
+ {
+ { 3, { 0xffffffff, 0xffffffff, 0xffffffff, } },
+ { 1, { 0xffffffff, } },
+ { 4, { 0x00000001, 0xffffffff, 0xffffffff, 0xfffffffe } },
+ },
+ {
+ { 2, { 0xffffffff, 1 } },
+ { 1, { 0xffffffff, } },
+ { 3, { 0x00000001, 0xfffffffd, 1 } },
+ },
+ {
+ { 2, { 0xffffffff, 1 } },
+ { 1, { 0xffffffff, } },
+ { 3, { 0x00000001, 0xfffffffd, 1 } },
+ },
+ {
+ { 2, { 1, 1 } },
+ { 2, { 1, 1 } },
+ { 3, { 1, 2, 1 } },
+ },
+ {
+ { 3, { 0xffffffff, 0xffffffff, 1 } },
+ { 2, { 0xffffffff, 0xffffffff } },
+ { 5, { 1, 0, 0xfffffffd, 0xffffffff, 1 } },
+ },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ Vint x, y, z, t;
+ x.setArray(tbl[i].a.p, tbl[i].a.n);
+ y.setArray(tbl[i].b.p, tbl[i].b.n);
+ z.setArray(tbl[i].c.p, tbl[i].c.n);
+ Vint::mul(t, x, y);
+ CYBOZU_TEST_EQUAL(t, z);
+
+ Vint::mul(t, y, x);
+ CYBOZU_TEST_EQUAL(t, z);
+ }
+ {
+ const uint32_t in[] = { 0xffffffff, 1 };
+ const uint32_t out[] = { 1, 0xfffffffc, 3 };
+ Vint x, y, z;
+ y.setArray(out, 3);
+ x.setArray(in, 2);
+ z = x;
+ Vint::mul(x, x, x);
+ CYBOZU_TEST_EQUAL(x, y);
+
+ x.setArray(in, 2);
+ Vint::mul(x, x, z);
+ CYBOZU_TEST_EQUAL(x, y);
+
+ x.setArray(in, 2);
+ Vint::mul(x, z, x);
+ CYBOZU_TEST_EQUAL(x, y);
+
+ x.setArray(in, 2);
+ Vint::mul(x, z, z);
+ CYBOZU_TEST_EQUAL(x, y);
+ }
+ {
+ Vint a("285434247217355341057");
+ a *= a;
+ CYBOZU_TEST_EQUAL(a, Vint("81472709484538325259309302444004789877249"));
+ }
+}
+
+CYBOZU_TEST_AUTO(div1)
+{
+ static const struct {
+ V a;
+ unsigned int b;
+ unsigned int r;
+ V c;
+ } tbl[] = {
+ {
+ { 1, { 100, } },
+ 1, 0,
+ { 1, { 100, } },
+ },
+ {
+ { 1, { 100, } },
+ 100, 0,
+ { 1, { 1, } },
+ },
+ {
+ { 1, { 100, } },
+ 101, 100,
+ { 1, { 0, } },
+ },
+ {
+ { 1, { 100, } },
+ 2, 0,
+ { 1, { 50, } },
+ },
+ {
+ { 1, { 100, } },
+ 3, 1,
+ { 1, { 33, } },
+ },
+ {
+ { 2, { 0xffffffff, 0xffffffff } },
+ 1, 0,
+ { 2, { 0xffffffff, 0xffffffff, } },
+ },
+ {
+ { 2, { 0xffffffff, 0xffffffff } },
+ 123, 15,
+ { 2, { 0x4d0214d0, 0x214d021 } },
+ },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ Vint x, z, t;
+ unsigned int b, r, u;
+ x.setArray(tbl[i].a.p, tbl[i].a.n);
+ b = tbl[i].b;
+ r = tbl[i].r;
+ z.setArray(tbl[i].c.p, tbl[i].c.n);
+
+ u = (unsigned int)Vint::divMods1(&t, x, b);
+ CYBOZU_TEST_EQUAL(t, z);
+ CYBOZU_TEST_EQUAL(u, r);
+
+ u = (unsigned int)Vint::divMods1(&x, x, b);
+ CYBOZU_TEST_EQUAL(x, z);
+ CYBOZU_TEST_EQUAL(u, r);
+ }
+}
+
+CYBOZU_TEST_AUTO(div2)
+{
+ static const struct {
+ V x;
+ V y;
+ V q;
+ V r;
+ } tbl[] = {
+ {
+ { 1, { 100 } },
+ { 1, { 3 } },
+ { 1, { 33 } },
+ { 1, { 1 } },
+ },
+ {
+ { 2, { 1, 1 } },
+ { 2, { 0, 1 } },
+ { 1, { 1 } },
+ { 1, { 1 } },
+ },
+ {
+ { 2, { 0xffffffff, 0xffffffff } },
+ { 2, { 0, 1 } },
+ { 1, { 0xffffffff } },
+ { 1, { 0xffffffff } },
+ },
+ {
+ { 2, { 0xffffffff, 0xffffffff } },
+ { 2, { 0xffffffff, 1 } },
+ { 1, { 0x80000000 } },
+ { 1, { 0x7fffffff } },
+ },
+ {
+ { 3, { 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 2, { 0xffffffff, 1 } },
+ { 2, { 0x40000000, 0x80000000 } },
+ { 1, { 0x3fffffff } },
+ },
+ {
+ { 4, { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 3, { 1, 0, 1 } },
+ { 2, { 0xffffffff, 0xffffffff } },
+ { 1, { 0 } },
+ },
+ {
+ { 4, { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 3, { 1, 0xffffffff, 0xffffffff } },
+ { 2, { 0, 1 } },
+ { 2, { 0xffffffff, 0xfffffffe } },
+ },
+ {
+ { 4, { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } },
+ { 3, { 1, 0, 0xffffffff } },
+ { 2, { 1, 1 } },
+ { 2, { 0xfffffffe, 0xfffffffe } },
+ },
+ {
+ { 4, { 0xffffffff, 0xffffffff, 0xffffffff, 1 } },
+ { 3, { 1, 0, 0xffffffff } },
+ { 1, { 2 } },
+ { 3, { 0xfffffffd, 0xffffffff, 1 } },
+ },
+ {
+ { 4, { 0, 0, 1, 1 } },
+ { 2, { 1, 1 } },
+ { 3, { 0, 0, 1 } },
+ { 1, { 0 } },
+ },
+ {
+ { 3, { 5, 5, 1} },
+ { 2, { 1, 2 } },
+ { 1, { 0x80000002 } },
+ { 1, { 0x80000003, } },
+ },
+ {
+ { 2, { 5, 5} },
+ { 2, { 1, 1 } },
+ { 1, { 5 } },
+ { 1, { 0, } },
+ },
+ {
+ { 2, { 5, 5} },
+ { 2, { 2, 1 } },
+ { 1, { 4 } },
+ { 1, { 0xfffffffd, } },
+ },
+ {
+ { 3, { 5, 0, 5} },
+ { 3, { 2, 0, 1 } },
+ { 1, { 4 } },
+ { 2, { 0xfffffffd, 0xffffffff } },
+ },
+ {
+ { 2, { 4, 5 } },
+ { 2, { 5, 5 } },
+ { 1, { 0 } },
+ { 2, { 4, 5 } },
+ },
+ {
+ { 1, { 123 } },
+ { 2, { 1, 1 } },
+ { 1, { 0 } },
+ { 1, { 123 } },
+ },
+ {
+ { 1, { 123 } },
+ { 3, { 1, 1, 1 } },
+ { 1, { 0 } },
+ { 1, { 123 } },
+ },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ Vint x, y, q, r;
+ x.setArray(tbl[i].x.p, tbl[i].x.n);
+ y.setArray(tbl[i].y.p, tbl[i].y.n);
+ q.setArray(tbl[i].q.p, tbl[i].q.n);
+ r.setArray(tbl[i].r.p, tbl[i].r.n);
+
+ Vint qt, rt;
+ Vint::quotRem(&qt, rt, x, y);
+ CYBOZU_TEST_EQUAL(qt, q);
+ CYBOZU_TEST_EQUAL(rt, r);
+
+ Vint::mul(y, y, qt);
+ Vint::add(y, y, rt);
+ CYBOZU_TEST_EQUAL(x, y);
+
+ x.setArray(tbl[i].x.p, tbl[i].x.n);
+ y.setArray(tbl[i].y.p, tbl[i].y.n);
+ Vint::quotRem(&x, rt, x, y);
+ CYBOZU_TEST_EQUAL(x, q);
+ CYBOZU_TEST_EQUAL(rt, r);
+
+ x.setArray(tbl[i].x.p, tbl[i].x.n);
+ y.setArray(tbl[i].y.p, tbl[i].y.n);
+ Vint::quotRem(&y, rt, x, y);
+ CYBOZU_TEST_EQUAL(y, q);
+ CYBOZU_TEST_EQUAL(rt, r);
+
+ x.setArray(tbl[i].x.p, tbl[i].x.n);
+ y.setArray(tbl[i].y.p, tbl[i].y.n);
+ Vint::quotRem(&x, y, x, y);
+ CYBOZU_TEST_EQUAL(x, q);
+ CYBOZU_TEST_EQUAL(y, r);
+
+ x.setArray(tbl[i].x.p, tbl[i].x.n);
+ y.setArray(tbl[i].y.p, tbl[i].y.n);
+ Vint::quotRem(&y, x, x, y);
+ CYBOZU_TEST_EQUAL(y, q);
+ CYBOZU_TEST_EQUAL(x, r);
+ }
+ {
+ const uint32_t in[] = { 1, 1 };
+ Vint x, y, z;
+ x.setArray(in, 2);
+ Vint::quotRem(&x, y, x, x);
+ z = 1;
+ CYBOZU_TEST_EQUAL(x, z);
+ z.clear();
+ CYBOZU_TEST_EQUAL(y, z);
+
+ Vint::quotRem(&y, x, x, x);
+ z = 1;
+ CYBOZU_TEST_EQUAL(y, z);
+ z.clear();
+ CYBOZU_TEST_EQUAL(x, z);
+ }
+}
+
+CYBOZU_TEST_AUTO(quotRem)
+{
+ const struct {
+ const char *x;
+ const char *y;
+ const char *r;
+ } tbl[] = {
+ {
+ "1448106640508192452750709206294683535529268965445799785581837640324321797831381715960812126274894517677713278300997728292641936248881345120394299128611830",
+ "82434016654300679721217353503190038836571781811386228921167322412819029493183",
+ "72416512377294697540770834088766459385112079195086911762075702918882982361282"
+ },
+ {
+ "97086308670107713719105336221824613370040805954034005192338040686500414395543303807941158656814978071549225072789349941064484974666540443679601226744652",
+ "82434016654300679721217353503190038836571781811386228921167322412819029493183",
+ "41854959563040430269871677548536437787164514279279911478858426970427834388586",
+ },
+ {
+ "726838724295606887174238120788791626017347752989142414466410919788841485181240131619880050064495352797213258935807786970844241989010252",
+ "82434016654300679721217353503190038836571781811386228921167322412819029493183",
+ "81378967132566843036693176764684783485107373533583677681931133755003929106966",
+ },
+ {
+ "85319207237201203511459960875801690195851794174784746933408178697267695525099750",
+ "82434016654300679721217353503190038836571781811386228921167322412819029493183",
+ "82434016654300679721217353503190038836571781811386228921167322412819029148528",
+ },
+ {
+ "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0x100000000000000000000000000000000000000000000000001",
+ "1606938044258990275541962092341162602522202993782724115824640",
+ },
+ {
+ "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0x1000000000000000000000000000000000000000000000000000000000000000000000000000000001",
+ "34175792574734561318320347298712833833643272357332299899995954578095372295314880347335474659983360",
+ },
+ {
+ "0xfffffffffffff000000000000000000000000000000000000000000000000000000000000000000",
+ "0x100000000000000000000000000000000000000000000000000000000000000000001",
+ "7558907585412001237250713901367146624661464598973016020495791084036551510708977665",
+ },
+ {
+ "0xfffffffffffff000000000000000000000000000000000000000000000000000000000000000000",
+ "0xfffffffffffff0000000000000000000000000000000000000000000000000000000000000001",
+ "521481209941628322292632858916605385658190900090571826892867289394157573281830188869820088065",
+ },
+ {
+ "0x1230000000000000456",
+ "0x1230000000000000457",
+ "0x1230000000000000456",
+ },
+ {
+ "0x1230000000000000456",
+ "0x1230000000000000456",
+ "0",
+ },
+ {
+ "0x1230000000000000456",
+ "0x1230000000000000455",
+ "1",
+ },
+ {
+ "0x1230000000000000456",
+ "0x2000000000000000000",
+ "0x1230000000000000456",
+ },
+ {
+ "0xffffffffffffffffffffffffffffffff",
+ "0x80000000000000000000000000000000",
+ "0x7fffffffffffffffffffffffffffffff",
+ },
+ {
+ "0xffffffffffffffffffffffffffffffff",
+ "0x7fffffffffffffffffffffffffffffff",
+ "1",
+ },
+ {
+ "0xffffffffffffffffffffffffffffffff",
+ "0x70000000000000000000000000000000",
+ "0x1fffffffffffffffffffffffffffffff",
+ },
+ {
+ "0xffffffffffffffffffffffffffffffff",
+ "0x30000000000000000000000000000000",
+ "0x0fffffffffffffffffffffffffffffff",
+ },
+ {
+ "0xffffffffffffffffffffffffffffffff",
+ "0x10000000000000000000000000000000",
+ "0x0fffffffffffffffffffffffffffffff",
+ },
+ {
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0x2523648240000001ba344d80000000086121000000000013a700000000000013",
+ "0x212ba4f27ffffff5a2c62effffffffcdb939ffffffffff8a15ffffffffffff8d",
+ },
+ {
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0x2523648240000001ba344d8000000007ff9f800000000010a10000000000000d",
+ "0x212ba4f27ffffff5a2c62effffffffd00242ffffffffff9c39ffffffffffffb1",
+ },
+ };
+ mcl::Vint x, y, q, r1, r2;
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ x.setStr(tbl[i].x);
+ y.setStr(tbl[i].y);
+ r1.setStr(tbl[i].r);
+ mcl::Vint::divMod(&q, r2, x, y);
+ CYBOZU_TEST_EQUAL(r1, r2);
+ CYBOZU_TEST_EQUAL(x, q * y + r2);
+ }
+}
+
+CYBOZU_TEST_AUTO(string)
+{
+ const struct {
+ uint32_t v[5];
+ size_t vn;
+ const char *str;
+ const char *hex;
+ const char *bin;
+ } tbl[] = {
+ { { 0 }, 0, "0", "0x0", "0b0" },
+ { { 12345 }, 1, "12345", "0x3039", "0b11000000111001" },
+ { { 0xffffffff }, 1, "4294967295", "0xffffffff", "0b11111111111111111111111111111111" },
+ { { 0, 1 }, 2, "4294967296", "0x100000000", "0b100000000000000000000000000000000" },
+ { { 0, 0, 0, 0, 1 }, 5, "340282366920938463463374607431768211456", "0x100000000000000000000000000000000", "0b100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" },
+ { { 0, 0x0b22a000, 0xe2f768a0, 0xe086b93c, 0x2cd76f }, 5, "1000000000000000000000000000000000000000000000", "0x2cd76fe086b93ce2f768a00b22a00000000000", "0b101100110101110110111111100000100001101011100100111100111000101111011101101000101000000000101100100010101000000000000000000000000000000000000000000000" },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ Vint x, y;
+ x.setArray(tbl[i].v,tbl[i].vn);
+ CYBOZU_TEST_EQUAL(x.getStr(10), tbl[i].str);
+ char buf[1024];
+ size_t n = x.getStr(buf, sizeof(buf), 10);
+ CYBOZU_TEST_ASSERT(n > 0);
+ CYBOZU_TEST_EQUAL(tbl[i].str, buf);
+ y.setStr(tbl[i].str);
+ CYBOZU_TEST_EQUAL(x.getStr(16), tbl[i].hex + 2);
+ n = x.getStr(buf, sizeof(buf), 16);
+ CYBOZU_TEST_ASSERT(n > 0);
+ CYBOZU_TEST_EQUAL(tbl[i].hex + 2, buf);
+ CYBOZU_TEST_EQUAL(x, y);
+ x = 1;
+ x.setStr(tbl[i].hex);
+ CYBOZU_TEST_EQUAL(x, y);
+ }
+}
+
+CYBOZU_TEST_AUTO(shift)
+{
+ Vint x("123423424918471928374192874198274981274918274918274918243");
+ Vint y, z;
+
+ const size_t unitBitSize = Vint::unitBitSize;
+ Vint s;
+ // shl
+ for (size_t i = 1; i < 31; i++) {
+ Vint::shl(y, x, i);
+ z = x * (Vint::Unit(1) << i);
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x << i;
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x;
+ y <<= i;
+ CYBOZU_TEST_EQUAL(y, z);
+ }
+ for (int i = 0; i < 4; i++) {
+ Vint::shl(y, x, i * unitBitSize);
+ Vint::pow(s, Vint(2), i * unitBitSize);
+ z = x * s;
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x << (i * unitBitSize);
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x;
+ y <<= (i * unitBitSize);
+ CYBOZU_TEST_EQUAL(y, z);
+ }
+ for (int i = 0; i < 100; i++) {
+ y = x << i;
+ Vint::pow(s, Vint(2), i);
+ z = x * s;
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x;
+ y <<= i;
+ CYBOZU_TEST_EQUAL(y, z);
+ }
+
+ // shr
+ for (size_t i = 1; i < 31; i++) {
+ Vint::shr(y, x, i);
+ z = x / (Vint::Unit(1) << i);
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x >> i;
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x;
+ y >>= i;
+ CYBOZU_TEST_EQUAL(y, z);
+ }
+ for (int i = 0; i < 3; i++) {
+ Vint::shr(y, x, i * unitBitSize);
+ Vint::pow(s, Vint(2), i * unitBitSize);
+ z = x / s;
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x >> (i * unitBitSize);
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x;
+ y >>= (i * unitBitSize);
+ CYBOZU_TEST_EQUAL(y, z);
+ }
+ for (int i = 0; i < 100; i++) {
+ y = x >> i;
+ Vint::pow(s, Vint(2), i);
+ z = x / s;
+ CYBOZU_TEST_EQUAL(y, z);
+ y = x;
+ y >>= i;
+ CYBOZU_TEST_EQUAL(y, z);
+ }
+ {
+ Vint a = 0, zero = 0;
+ a <<= Vint::unitBitSize;
+ CYBOZU_TEST_EQUAL(a, zero);
+ }
+}
+
+CYBOZU_TEST_AUTO(getBitSize)
+{
+ {
+ Vint zero = 0;
+ CYBOZU_TEST_EQUAL(zero.getBitSize(), 1);
+ zero <<= (Vint::unitBitSize - 1);
+ CYBOZU_TEST_EQUAL(zero.getBitSize(), 1);
+ zero <<= Vint::unitBitSize;
+ CYBOZU_TEST_EQUAL(zero.getBitSize(), 1);
+ }
+
+ {
+ Vint a = 1;
+ CYBOZU_TEST_EQUAL(a.getBitSize(), 1);
+ a = 2;
+ CYBOZU_TEST_EQUAL(a.getBitSize(), 2);
+ a = 3;
+ CYBOZU_TEST_EQUAL(a.getBitSize(), 2);
+ a = 4;
+ CYBOZU_TEST_EQUAL(a.getBitSize(), 3);
+ }
+
+ {
+ Vint a = 5;
+ const size_t msbindex = a.getBitSize();
+ const size_t width = 100;
+ const size_t time = 3;
+ for (size_t i = 0; i < time; ++i) {
+ a <<= width;
+ CYBOZU_TEST_EQUAL(a.getBitSize(), msbindex + width*(i + 1));
+ }
+
+ for (size_t i = 0; i < time*2; ++i) {
+ a >>= width/2;
+ CYBOZU_TEST_EQUAL(a.getBitSize(), msbindex + width*time - (width/2)*(i + 1));
+ }
+ a >>= width;
+ CYBOZU_TEST_ASSERT(a.isZero());
+ CYBOZU_TEST_EQUAL(a.getBitSize(), 1);
+ }
+
+ {
+ Vint b("12"), c("345"), d("67890");
+ size_t bl = b.getBitSize(), cl = c.getBitSize(), dl = d.getBitSize();
+ CYBOZU_TEST_ASSERT((b*c).getBitSize() <= bl + cl);
+ CYBOZU_TEST_ASSERT((c*d).getBitSize() <= cl + dl);
+ CYBOZU_TEST_ASSERT((b*c*d).getBitSize() <= bl + cl + dl);
+ }
+}
+
+CYBOZU_TEST_AUTO(bit)
+{
+ Vint a;
+ a.setStr("0x1234567890abcdef");
+ bool tvec[] = {
+ 1,1,1,1,0 ,1,1,1,1,0
+ ,1,1,0,0,1 ,1,1,1,0,1
+ ,0,1,0,1,0 ,0,0,0,1,0
+ ,0,1,0,0,0 ,1,1,1,1,0
+ ,0,1,1,0,1 ,0,1,0,0,0
+ ,1,0,1,1,0 ,0,0,1,0,0
+ ,1
+ };
+ CYBOZU_TEST_EQUAL(a.getBitSize(), sizeof(tvec)/sizeof(*tvec));
+ for (int i = (int)a.getBitSize() - 1; i >= 0; --i) {
+ CYBOZU_TEST_EQUAL(a.testBit(i), tvec[i]);
+ }
+}
+
+CYBOZU_TEST_AUTO(sample)
+{
+ using namespace mcl;
+ Vint x(1);
+ Vint y("123456789");
+ Vint z;
+
+ x = 1; // set by int
+ y.setStr("123456789"); // set by decimal
+ z.setStr("0xffffffff"); // set by hex
+ x += z;
+
+ x = 2;
+ y = 250;
+ Vint::pow(x, x, y);
+ Vint r, q;
+ r = x % y;
+ q = x / y;
+ CYBOZU_TEST_EQUAL(q * y + r, x);
+
+ Vint::quotRem(&q, r, x, y); // get both r and q
+ CYBOZU_TEST_EQUAL(q * y + r, x);
+}
+
+CYBOZU_TEST_AUTO(Vint)
+{
+ const struct {
+ int a;
+ int b;
+ /*
+ q, r ; like C
+ q2, r2 ; like Python
+ */
+ int add, sub, mul, q, r, q2, r2;
+ } tbl[] = {
+ { 13, 5, 18, 8, 65, 2, 3, 2, 3 },
+ { 13, -5, 8, 18, -65, -2, 3, -3, -2 },
+ { -13, 5, -8, -18, -65, -2, -3, -3, 2 },
+ { -13, -5, -18, -8, 65, 2, -3, 2, -3 },
+ { 5, 13, 18, -8, 65, 0, 5 , 0, 5},
+ { 5, -13, -8, 18, -65, 0, 5 , -1, -8},
+ { -5, 13, 8, -18, -65, 0, -5 , -1, 8},
+ { -5, -13, -18, 8, 65, 0, -5 , 0, -5},
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ Vint a = tbl[i].a;
+ Vint b = tbl[i].b;
+ Vint add = a + b;
+ Vint sub = a - b;
+ Vint mul = a * b;
+ Vint q = a / b;
+ Vint r = a % b;
+ Vint q2, r2;
+ Vint::quotRem(&q2, r2, a, b);
+ CYBOZU_TEST_EQUAL(add, tbl[i].add);
+ CYBOZU_TEST_EQUAL(sub, tbl[i].sub);
+ CYBOZU_TEST_EQUAL(mul, tbl[i].mul);
+ CYBOZU_TEST_EQUAL(q, tbl[i].q);
+ CYBOZU_TEST_EQUAL(r, tbl[i].r);
+ CYBOZU_TEST_EQUAL(q * b + r, a);
+ CYBOZU_TEST_EQUAL(q2, tbl[i].q2);
+ CYBOZU_TEST_EQUAL(r2, tbl[i].r2);
+ CYBOZU_TEST_EQUAL(q2 * b + r2, a);
+ }
+ CYBOZU_TEST_EQUAL(Vint("15") / Vint("3"), Vint("5"));
+ CYBOZU_TEST_EQUAL(Vint("15") / Vint("-3"), Vint("-5"));
+ CYBOZU_TEST_EQUAL(Vint("-15") / Vint("3"), Vint("-5"));
+ CYBOZU_TEST_EQUAL(Vint("-15") / Vint("-3"), Vint("5"));
+
+ CYBOZU_TEST_EQUAL(Vint("15") % Vint("3"), Vint("0"));
+ CYBOZU_TEST_EQUAL(Vint("15") % Vint("-3"), Vint("0"));
+ CYBOZU_TEST_EQUAL(Vint("-15") % Vint("3"), Vint("0"));
+ CYBOZU_TEST_EQUAL(Vint("-15") % Vint("-3"), Vint("0"));
+
+ CYBOZU_TEST_EQUAL(Vint("-0") + Vint("-3"), Vint("-3"));
+ CYBOZU_TEST_EQUAL(Vint("-0") - Vint("-3"), Vint("3"));
+ CYBOZU_TEST_EQUAL(Vint("-3") + Vint("-0"), Vint("-3"));
+ CYBOZU_TEST_EQUAL(Vint("-3") - Vint("-0"), Vint("-3"));
+
+ CYBOZU_TEST_EQUAL(Vint("-0") + Vint("3"), Vint("3"));
+ CYBOZU_TEST_EQUAL(Vint("-0") - Vint("3"), Vint("-3"));
+ CYBOZU_TEST_EQUAL(Vint("3") + Vint("-0"), Vint("3"));
+ CYBOZU_TEST_EQUAL(Vint("3") - Vint("-0"), Vint("3"));
+
+ CYBOZU_TEST_EQUAL(Vint("0"), Vint("0"));
+ CYBOZU_TEST_EQUAL(Vint("0"), Vint("-0"));
+ CYBOZU_TEST_EQUAL(Vint("-0"), Vint("0"));
+ CYBOZU_TEST_EQUAL(Vint("-0"), Vint("-0"));
+
+ CYBOZU_TEST_ASSERT(Vint("2") < Vint("3"));
+ CYBOZU_TEST_ASSERT(Vint("-2") < Vint("3"));
+ CYBOZU_TEST_ASSERT(Vint("-5") < Vint("-3"));
+ CYBOZU_TEST_ASSERT(Vint("-0") < Vint("1"));
+ CYBOZU_TEST_ASSERT(Vint("-1") < Vint("-0"));
+
+ CYBOZU_TEST_ASSERT(Vint("5") > Vint("3"));
+ CYBOZU_TEST_ASSERT(Vint("5") > Vint("-3"));
+ CYBOZU_TEST_ASSERT(Vint("-2") > Vint("-3"));
+ CYBOZU_TEST_ASSERT(Vint("3") > Vint("-0"));
+ CYBOZU_TEST_ASSERT(Vint("-0") > Vint("-1"));
+
+ {
+ const struct {
+ const char *str;
+ int s;
+ int shl;
+ int shr;
+ } tbl2[] = {
+ { "0", 1, 0, 0 },
+ { "-0", 1, 0, 0 },
+ { "1", 1, 2, 0 },
+ { "-1", 1, -2, 0 },
+ { "12345", 3, 98760, 1543 },
+ { "-12345", 3, -98760, 0 },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl2); i++) {
+ Vint a = Vint(tbl2[i].str);
+ Vint shl = a << tbl2[i].s;
+ CYBOZU_TEST_EQUAL(shl, tbl2[i].shl);
+ if (!a.isNegative()) {
+ Vint shr = a >> tbl2[i].s;
+ CYBOZU_TEST_EQUAL(shr, tbl2[i].shr);
+ }
+ }
+ }
+}
+
+CYBOZU_TEST_AUTO(add2)
+{
+ Vint x, y, z, w;
+ x.setStr("2416089439321382744001761632872637936198961520379024187947524965775137204955564426500438089001375107581766516460437532995850581062940399321788596606850");
+ y.setStr("2416089439321382743300544243711595219403446085161565705825288050160594425031420687263897209379984490503106207071010949258995096347962762372787916800000");
+ z.setStr("701217389161042716795515435217458482122236915614542779924143739236540879621390617078660309389426583736855484714977636949000679806850");
+ Vint::sub(w, x, y);
+ CYBOZU_TEST_EQUAL(w, z);
+
+ Vint a, c, d;
+
+ a.setStr("-2416089439321382744001761632872637936198961520379024187947524965775137204955564426500438089001375107581766516460437532995850581062940399321788596606850");
+ c.setStr("2416089439321382743300544243711595219403446085161565705825288050160594425031420687263897209379984490503106207071010949258995096347962762372787916800000");
+ a = a + c;
+
+ d.setStr("-701217389161042716795515435217458482122236915614542779924143739236540879621390617078660309389426583736855484714977636949000679806850");
+ CYBOZU_TEST_EQUAL(a, d);
+}
+
+CYBOZU_TEST_AUTO(stream)
+{
+ {
+ Vint x, y, z, w;
+ x.setStr("12345678901232342424242423423429922");
+ y.setStr("23423423452424242343");
+ std::ostringstream oss;
+ oss << x << ' ' << y;
+ std::istringstream iss(oss.str());
+ iss >> z >> w;
+ CYBOZU_TEST_EQUAL(x, z);
+ CYBOZU_TEST_EQUAL(y, w);
+ }
+ {
+ Vint x, y, z, w;
+ x.setStr("0x100");
+ y.setStr("123");
+ std::ostringstream oss;
+ oss << x << ' ' << y;
+ std::istringstream iss(oss.str());
+ iss >> z >> w;
+ CYBOZU_TEST_EQUAL(x, z);
+ CYBOZU_TEST_EQUAL(y, w);
+ }
+ {
+ Vint x, y, z, w;
+ x.setStr("12345678901232342424242423423429922");
+ y.setStr("-23423423452424242343");
+ std::ostringstream oss;
+ oss << x << ' ' << y;
+ std::istringstream iss(oss.str());
+ iss >> z >> w;
+ CYBOZU_TEST_EQUAL(x, z);
+ CYBOZU_TEST_EQUAL(y, w);
+ }
+}
+
+CYBOZU_TEST_AUTO(inc_dec)
+{
+ Vint x = 3;
+ CYBOZU_TEST_EQUAL(x++, 3);
+ CYBOZU_TEST_EQUAL(x, 4);
+ CYBOZU_TEST_EQUAL(++x, 5);
+ CYBOZU_TEST_EQUAL(x, 5);
+
+ CYBOZU_TEST_EQUAL(x--, 5);
+ CYBOZU_TEST_EQUAL(x, 4);
+ CYBOZU_TEST_EQUAL(--x, 3);
+ CYBOZU_TEST_EQUAL(x, 3);
+}
+
+CYBOZU_TEST_AUTO(withInt)
+{
+ Vint x = 15;
+ x += 3;
+ CYBOZU_TEST_EQUAL(x, 18);
+ x -= 2;
+ CYBOZU_TEST_EQUAL(x, 16);
+ x *= 2;
+ CYBOZU_TEST_EQUAL(x, 32);
+ x /= 3;
+ CYBOZU_TEST_EQUAL(x, 10);
+ x = -x;
+ CYBOZU_TEST_EQUAL(x, -10);
+ x += 1;
+ CYBOZU_TEST_EQUAL(x, -9);
+ x -= 2;
+ CYBOZU_TEST_EQUAL(x, -11);
+ x *= 2;
+ CYBOZU_TEST_EQUAL(x, -22);
+ x /= 5;
+ CYBOZU_TEST_EQUAL(x, -4);
+ x = -22;
+ x %= 5;
+ CYBOZU_TEST_EQUAL(x, -2);
+
+ x = 3;
+ x += -2;
+ CYBOZU_TEST_EQUAL(x, 1);
+ x += -5;
+ CYBOZU_TEST_EQUAL(x, -4);
+ x -= -7;
+ CYBOZU_TEST_EQUAL(x, 3);
+ x *= -1;
+ CYBOZU_TEST_EQUAL(x, -3);
+ x /= -1;
+ CYBOZU_TEST_EQUAL(x, 3);
+
+ x++;
+ CYBOZU_TEST_EQUAL(x, 4);
+ x--;
+ CYBOZU_TEST_EQUAL(x, 3);
+ x = -3;
+ x++;
+ CYBOZU_TEST_EQUAL(x, -2);
+ x--;
+ CYBOZU_TEST_EQUAL(x, -3);
+
+ ++x;
+ CYBOZU_TEST_EQUAL(x, -2);
+ --x;
+ CYBOZU_TEST_EQUAL(x, -3);
+ x = 3;
+ ++x;
+ CYBOZU_TEST_EQUAL(x, 4);
+ --x;
+ CYBOZU_TEST_EQUAL(x, 3);
+}
+
+CYBOZU_TEST_AUTO(addu1)
+{
+ Vint x = 4;
+ Vint::addu1(x, x, 2);
+ CYBOZU_TEST_EQUAL(x, 6);
+ Vint::subu1(x, x, 2);
+ CYBOZU_TEST_EQUAL(x, 4);
+ Vint::subu1(x, x, 10);
+ CYBOZU_TEST_EQUAL(x, -6);
+ x = -4;
+ Vint::addu1(x, x, 2);
+ CYBOZU_TEST_EQUAL(x, -2);
+ Vint::subu1(x, x, 2);
+ CYBOZU_TEST_EQUAL(x, -4);
+ Vint::addu1(x, x, 10);
+ CYBOZU_TEST_EQUAL(x, 6);
+
+ x.setStr("0x10000000000000000000000002");
+ Vint::subu1(x, x, 3);
+ CYBOZU_TEST_EQUAL(x, Vint("0xfffffffffffffffffffffffff"));
+ x.setStr("-0x10000000000000000000000000");
+ Vint::addu1(x, x, 5);
+ CYBOZU_TEST_EQUAL(x, Vint("-0xffffffffffffffffffffffffb"));
+}
+
+CYBOZU_TEST_AUTO(pow)
+{
+ Vint x = 2;
+ Vint y;
+ Vint::pow(y, x, 3);
+ CYBOZU_TEST_EQUAL(y, 8);
+ x = -2;
+ Vint::pow(y, x, 3);
+ CYBOZU_TEST_EQUAL(y, -8);
+#ifndef MCL_AVOID_EXCEPTION_TEST
+// CYBOZU_TEST_EXCEPTION(Vint::pow(y, x, -2), cybozu::Exception);
+#endif
+}
+
+CYBOZU_TEST_AUTO(powMod)
+{
+ Vint x = 7;
+ Vint m = 65537;
+ Vint y;
+ Vint::powMod(y, x, 20, m);
+ CYBOZU_TEST_EQUAL(y, 55277);
+ Vint::powMod(y, x, m - 1, m);
+ CYBOZU_TEST_EQUAL(y, 1);
+}
+
+CYBOZU_TEST_AUTO(andOr)
+{
+ Vint x("1223480928420984209849242");
+ Vint y("29348220482094820948208420984209482048204289482");
+ Vint z;
+ z = x & y;
+ CYBOZU_TEST_EQUAL(z, Vint("1209221003550923564822922"));
+ z = x | y;
+ CYBOZU_TEST_EQUAL(z, Vint("29348220482094820948208435244134352108849315802"));
+#ifndef MCL_AVOID_EXCEPTION_TEST
+// CYBOZU_TEST_EXCEPTION(Vint("-2") | Vint("5"), cybozu::Exception);
+// CYBOZU_TEST_EXCEPTION(Vint("-2") & Vint("5"), cybozu::Exception);
+#endif
+ x = 8;
+ x |= 7;
+ CYBOZU_TEST_EQUAL(x, 15);
+ x = 65536;
+ y = 8;
+ y &= x;
+ CYBOZU_TEST_EQUAL(y, 0);
+}
+
+CYBOZU_TEST_AUTO(invMod)
+{
+ Vint m("100000000000000000039");
+ for (int i = 1; i < 100; i++) {
+ Vint x = i;
+ Vint y;
+ Vint::invMod(y, x, m);
+ CYBOZU_TEST_EQUAL((y * x) % m, 1);
+ }
+}
+
+CYBOZU_TEST_AUTO(isPrime)
+{
+ int primeTbl[] = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
+ 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
+ 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,197, 199, 211,
+ 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
+ 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379,
+ 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461,
+ 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563,
+ 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643,
+ 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739,
+ 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
+ 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937,
+ 941, 947, 953, 967, 971, 977, 983, 991, 997
+ };
+ typedef std::set<int> IntSet;
+ IntSet primes;
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(primeTbl); i++) {
+ primes.insert(primeTbl[i]);
+ }
+ for (int i = 0; i < 1000; i++) {
+ bool ok = primes.find(i) != primes.end();
+ bool my = Vint(i).isPrime();
+ CYBOZU_TEST_EQUAL(ok, my);
+ }
+ const struct {
+ const char *n;
+ bool isPrime;
+ } tbl[] = {
+ { "65537", true },
+ { "449065", false },
+ { "488881", false },
+ { "512461", false },
+ { "18446744073709551629", true },
+ { "18446744073709551631", false },
+ { "0x10000000000000000000000000000000000000007", true },
+ { "0x10000000000000000000000000000000000000009", false },
+ { "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", true },
+ { "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", false },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ Vint x(tbl[i].n);
+ CYBOZU_TEST_EQUAL(x.isPrime(), tbl[i].isPrime);
+ }
+}
+
+CYBOZU_TEST_AUTO(gcd)
+{
+ Vint x = 12;
+ Vint y = 18;
+ Vint z;
+ Vint::gcd(z, x, y);
+ CYBOZU_TEST_EQUAL(z, 6);
+ Vint::lcm(z, x, y);
+ CYBOZU_TEST_EQUAL(z, 36);
+ Vint::lcm(x, x, y);
+ CYBOZU_TEST_EQUAL(x, 36);
+ Vint::lcm(x, x, x);
+ CYBOZU_TEST_EQUAL(x, 36);
+}
+
+CYBOZU_TEST_AUTO(jacobi)
+{
+ const struct {
+ const char *m;
+ const char *n;
+ int ok;
+ } tbl[] = {
+ { "0", "1", 1 },
+ { "1", "1", 1 },
+ { "123", "1", 1 },
+ { "45", "77", -1 },
+ { "60", "121", 1 },
+ { "12345672342342342342428", "923423423424753211", 1 },
+ { "12345672342342342342428","34592342234235424753211", -1 },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ int my = Vint::jacobi(Vint(tbl[i].m), Vint(tbl[i].n));
+ CYBOZU_TEST_EQUAL(my, tbl[i].ok);
+ }
+}
+
+CYBOZU_TEST_AUTO(bench)
+{
+ Vint x, y, z;
+ x.setStr("0x2523648240000001ba344d80000000086121000000000013a700000000000013");
+ y.setStr("0x1802938109810498104982094820498203942804928049284092424902424243");
+
+ int N = 100000;
+ CYBOZU_BENCH_C("add", N, Vint::add, z, x, y);
+ CYBOZU_BENCH_C("sub", N, Vint::sub, z, x, y);
+ CYBOZU_BENCH_C("mul", N, Vint::mul, z, x, y);
+ CYBOZU_BENCH_C("div", N, Vint::div, y, z, x);
+
+ const struct {
+ const char *x;
+ const char *y;
+ } tbl[] = {
+ {
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0x2523648240000001ba344d8000000007ff9f800000000010a10000000000000d"
+ },
+ {
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab",
+ },
+ {
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001",
+ },
+
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ x.setStr(tbl[i].x);
+ y.setStr(tbl[i].y);
+ CYBOZU_BENCH_C("fast div", N, Vint::div, z, x, y);
+#ifndef DONT_USE_GMP_IN_TEST
+ {
+ mpz_class mx(tbl[i].x), my(tbl[i].y), mz;
+ CYBOZU_BENCH_C("gmp", N, mpz_div, mz.get_mpz_t(), mx.get_mpz_t(), my.get_mpz_t());
+ }
+#endif
+ }
+}
+
+struct Seq {
+ const uint32_t *tbl;
+ size_t n;
+ size_t i, j;
+ Seq(const uint32_t *tbl, size_t n) : tbl(tbl), n(n), i(0), j(0) {}
+ bool next(uint64_t *v)
+ {
+ if (i == n) {
+ if (j == n - 1) return false;
+ i = 0;
+ j++;
+ }
+ *v = (uint64_t(tbl[j]) << 32) | tbl[i];
+ i++;
+ return true;
+ }
+};
+
+#if MCL_SIZEOF_UNIT == 8
+CYBOZU_TEST_AUTO(divUnit)
+{
+ const uint32_t tbl[] = {
+ 0, 1, 3,
+ 0x7fffffff,
+ 0x80000000,
+ 0x80000001,
+ 0xffffffff,
+ };
+ const size_t n = sizeof(tbl) / sizeof(tbl[0]);
+ Seq seq3(tbl, n);
+ uint64_t y;
+ while (seq3.next(&y)) {
+ if (y == 0) continue;
+ Seq seq2(tbl, n);
+ uint64_t r;
+ while (seq2.next(&r)) {
+ if (r >= y) break;
+ Seq seq1(tbl, n);
+ uint64_t q;
+ while (seq1.next(&q)) {
+ uint64_t x[2];
+ x[0] = mcl::vint::mulUnit(&x[1], q, y);
+ mcl::vint::addu1(x, x, 2, r);
+ uint64_t Q, R;
+//printf("q=0x%016llxull, r=0x%016llxull, y=0x%016llxull\n", (long long)q, (long long)r, (long long)y);
+ Q = mcl::vint::divUnit(&R, x[1], x[0], y);
+ CYBOZU_TEST_EQUAL(q, Q);
+ CYBOZU_TEST_EQUAL(r, R);
+ }
+ }
+ }
+}
+
+void compareMod(const uint64_t *x, const uint64_t *p)
+{
+ uint64_t y1[4] = {};
+ uint64_t y2[4] = {};
+ mcl::vint::divNM((uint64_t*)0, 0, y1, x, 8, p, 4);
+ mcl::vint::mcl_fpDbl_mod_SECP256K1(y2, x, p);
+ CYBOZU_TEST_EQUAL_ARRAY(y1, y2, 4);
+}
+CYBOZU_TEST_AUTO(SECP256k1)
+{
+ const uint64_t F = uint64_t(-1);
+ const uint64_t p[4] = { uint64_t(0xfffffffefffffc2full), F, F, F };
+ const uint64_t tbl[][8] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { F, F, F, F, F, F, F, F },
+ { F, F, F, F, 1, 0, 0, 0 },
+ };
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
+ const uint64_t *x = tbl[i];
+ compareMod(x, p);
+ }
+ cybozu::XorShift rg;
+ for (size_t i = 0; i < 100; i++) {
+ uint64_t x[8];
+ for (int j = 0; j < 8; j++) {
+ x[j] = rg();
+ }
+ compareMod(x, p);
+ }
+}
+#endif