diff --git a/README.md b/README.md index 3a567b3..91b83da 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This package is a script that generates a Finite field Library in Intel64 / ARM6 ## Usage -install g++ nasm ang gmp library if you don't have it. +install g++ and nasm if you don't have them. ``` npm install -g ffiasm @@ -17,7 +17,7 @@ cd myProject buildzqfield -q 21888242871839275222246405745257275088548364400416034343698204186575808495617 -n Fr ``` -You now will have two files fr.cpp, fr.hpp and fr.asm +You now will have fr.cpp, fr.hpp, fr.asm, mp.cpp, and mp.hpp ``` ls @@ -66,7 +66,7 @@ int main() { Compile it ``` -g++ main.cpp fr.o fr.cpp -o example -lgmp +g++ main.cpp fr.o fr.cpp mp.cpp -o example ``` Run it diff --git a/c/alt_bn128_test.cpp b/c/alt_bn128_test.cpp index ddcc5ad..925408d 100644 --- a/c/alt_bn128_test.cpp +++ b/c/alt_bn128_test.cpp @@ -1,16 +1,18 @@ -#include #include +#include +#include #include "gtest/gtest.h" #include "alt_bn128.hpp" #include "fft.hpp" - +#include +#include +#include using namespace AltBn128; namespace { TEST(altBn128, f2_simpleMul) { - F2Element e1; F2.fromString(e1, "(2,2)"); @@ -23,8 +25,6 @@ TEST(altBn128, f2_simpleMul) { F2Element e33; F2.fromString(e33, "(0,12)"); - // std::cout << F2.toString(e3) << std::endl; - ASSERT_TRUE(F2.eq(e3, e33)); } @@ -94,17 +94,13 @@ TEST(altBn128, f12_inv) { TEST(altBn128, g1_PlusZero) { G1Point p1; - G1.add(p1, G1.one(), G1.zero()); - ASSERT_TRUE(G1.eq(p1, G1.one())); } TEST(altBn128, g1_minus_g1) { G1Point p1; - G1.sub(p1, G1.one(), G1.one()); - ASSERT_TRUE(G1.isZero(p1)); } @@ -121,7 +117,6 @@ TEST(altBn128, g1_times_4) { ASSERT_TRUE(G1.eq(p1,p2)); } - TEST(altBn128, g1_times_3) { G1Point p1; G1.add(p1, G1.one(), G1.one()); @@ -140,16 +135,13 @@ TEST(altBn128, g1_times_3_exp) { G1.add(p1, G1.one(), G1.one()); G1.add(p1, p1, G1.one()); - mpz_t e; - mpz_init_set_str(e, "3", 10); - - uint8_t scalar[32]; - for (int i=0;i<32;i++) scalar[i] = 0; - mpz_export((void *)scalar, NULL, -1, 8, -1, 0, e); - mpz_clear(e); + mp_uint_t scalar; + mp_uint_t x; + mp_set(x, 3); + mp_copy(scalar, x); G1Point p2; - G1.mulByScalar(p2, G1.one(), scalar, 32); + G1.mulByScalar(p2, G1.one(), (uint8_t*)scalar, MP_N); ASSERT_TRUE(G1.eq(p1,p2)); } @@ -175,7 +167,6 @@ TEST(altBn128, g1_times_5) { } TEST(altBn128, g1_times_65_exp) { - G1Point p1; G1.dbl(p1, G1.one()); G1.dbl(p1, p1); @@ -185,140 +176,215 @@ TEST(altBn128, g1_times_65_exp) { G1.dbl(p1, p1); G1.add(p1, p1, G1.one()); - mpz_t e; - mpz_init_set_str(e, "65", 10); - - uint8_t scalar[32]; - for (int i=0;i<32;i++) scalar[i] = 0; - mpz_export((void *)scalar, NULL, -1, 8, -1, 0, e); - mpz_clear(e); + mp_uint_t scalar; + mp_uint_t x; + mp_set(x, 65); + mp_copy(scalar, x); G1Point p2; - G1.mulByScalar(p2, G1.one(), scalar, 32); + G1.mulByScalar(p2, G1.one(), (uint8_t*)scalar, MP_N); ASSERT_TRUE(G1.eq(p1,p2)); } TEST(altBn128, g1_expToOrder) { - mpz_t e; - mpz_init_set_str(e, "21888242871839275222246405745257275088548364400416034343698204186575808495617", 10); - - uint8_t scalar[32]; - - for (int i=0;i<32;i++) scalar[i] = 0; - mpz_export((void *)scalar, NULL, -1, 8, -1, 0, e); - mpz_clear(e); + mp_uint_t scalar; + mp_uint_t x; + ASSERT_TRUE(mp_set(x, + "21888242871839275222246405745257275088548364400416034343698204186575808495617", + 10 + )); + mp_copy(scalar, x); G1Point p1; - - G1.mulByScalar(p1, G1.one(), scalar, 32); + G1.mulByScalar(p1, G1.one(), (uint8_t *)scalar, MP_N); ASSERT_TRUE(G1.isZero(p1)); } TEST(altBn128, g2_expToOrder) { - mpz_t e; - mpz_init_set_str(e, "21888242871839275222246405745257275088548364400416034343698204186575808495617", 10); - - uint8_t scalar[32]; - - for (int i=0;i<32;i++) scalar[i] = 0; - mpz_export((void *)scalar, NULL, -1, 8, -1, 0, e); - mpz_clear(e); + mp_uint_t scalar; + mp_uint_t x; + ASSERT_TRUE(mp_set(x, + "21888242871839275222246405745257275088548364400416034343698204186575808495617", + 10 + )); + mp_copy(scalar, x); Curve>::Point p1; - - G2.mulByScalar(p1, G2.one(), scalar, 32); + G2.mulByScalar(p1, G2.one(), (uint8_t *)scalar, MP_N); ASSERT_TRUE(G2.isZero(p1)); } -TEST(altBn128, multiExp) { - +TEST(altBn128, multiExp_old) { int NMExp = 40000; - typedef uint8_t Scalar[32]; + typedef mp_uint_t Scalar; Scalar *scalars = new Scalar[NMExp]; G1PointAffine *bases = new G1PointAffine[NMExp]; - uint64_t acc=0; - for (int i=0; i fn) { + auto t0 = perf_clock::now(); + fn(); + auto t1 = perf_clock::now(); + return std::chrono::duration(t1 - t0).count(); +} + +static inline double ns_per_op(double ms, size_t n) { + return (ms * 1e6) / (double)n; +} + +TEST(altBn128Perf, g1_curve_ops_timing_nogmp) { + G1PointAffine a_aff, b_aff, c_aff; + G1.copy(a_aff, G1.one()); // P + G1.add(b_aff, a_aff, G1.one()); // 2P + G1.add(c_aff, b_aff, G1.one()); // 3P + + G1Point a_jac, b_jac, c_jac; + G1.copy(a_jac, a_aff); + G1.copy(b_jac, b_aff); + G1.copy(c_jac, c_aff); + + const size_t N_MIXED = 300000; + const size_t N_FULL = 200000; + const size_t N_DBL = 300000; + + G1Point acc_mixed; + G1.copy(acc_mixed, a_jac); + double ms_mixed = bench_ms([&]() { + for (size_t i = 0; i < N_MIXED; i++) { + G1.add(acc_mixed, acc_mixed, b_aff); + } + }); + + G1Point acc_full; + G1.copy(acc_full, a_jac); + double ms_full = bench_ms([&]() { + for (size_t i = 0; i < N_FULL; i++) { + G1.add(acc_full, acc_full, b_jac); + } + }); + + G1Point acc_dbl; + G1.copy(acc_dbl, c_jac); + double ms_dbl = bench_ms([&]() { + for (size_t i = 0; i < N_DBL; i++) { + G1.dbl(acc_dbl, acc_dbl); + } + }); + + ASSERT_FALSE(G1.isZero(acc_mixed)); + ASSERT_FALSE(G1.isZero(acc_full)); + ASSERT_FALSE(G1.isZero(acc_dbl)); + + std::cout << std::fixed << std::setprecision(3); + std::cout << "[perf][nogmp] G1.add mixed : " << ms_mixed << " ms (N=" << N_MIXED + << ") => " << ns_per_op(ms_mixed, N_MIXED) << " ns/op\n"; + std::cout << "[perf][nogmp] G1.add full : " << ms_full << " ms (N=" << N_FULL + << ") => " << ns_per_op(ms_full, N_FULL) << " ns/op\n"; + std::cout << "[perf][nogmp] G1.dbl : " << ms_dbl << " ms (N=" << N_DBL + << ") => " << ns_per_op(ms_dbl, N_DBL) << " ns/op\n"; +} + +TEST(altBn128Perf, multiexp_phases_timing_nogmp) { + const int NMExp = 40000; + + typedef mp_uint_t Scalar; + + Scalar *scalars = new Scalar[NMExp]; + G1PointAffine *bases = new G1PointAffine[NMExp]; + + double ms_prepare = bench_ms([&]() { + for (int i = 0; i < NMExp; i++) { + if (i == 0) { + G1.copy(bases[0], G1.one()); + } else { + G1.add(bases[i], bases[i - 1], G1.one()); + } + + mp_uint_t x; + mp_set(x, (uint64_t)(i + 1)); + mp_copy(scalars[i], x); + } + }); + + G1Point r1; + double ms_multiexp = bench_ms([&]() { + G1.multiMulByScalar(r1, bases, (uint8_t *)scalars, MP_N, NMExp); + }); + + G1Point r2; + double ms_msm = bench_ms([&]() { + G1.multiMulByScalarMSM(r2, bases, (uint8_t *)scalars, MP_N, NMExp); + }); + + ASSERT_FALSE(G1.isZero(r1)); + ASSERT_FALSE(G1.isZero(r2)); + + std::cout << std::fixed << std::setprecision(3); + std::cout << "[perf][nogmp] prepare bases/scalars : " << ms_prepare << " ms (N=" << NMExp << ")\n"; + std::cout << "[perf][nogmp] G1.multiMulByScalar : " << ms_multiexp << " ms (N=" << NMExp << ")\n"; + std::cout << "[perf][nogmp] G1.multiMulByScalarMSM: " << ms_msm << " ms (N=" << NMExp << ")\n"; + + delete[] bases; + delete[] scalars; +} + + + +TEST(altBn128Perf, affine_build_path_timing_nogmp) { + G1PointAffine p1_aff, p2_aff, out_aff; + G1.copy(p1_aff, G1.one()); + G1.add(p2_aff, p1_aff, G1.one()); // 2P as affine + + G1Point out_jac; + G1Point tmp_jac; + + const size_t N_ADD_AFFINE = 200000; + const size_t N_TO_AFFINE = 200000; + const size_t N_BUILD_STEP = 100000; + + // 1) pure affine+affine -> Jacobian + double ms_add_affine = bench_ms([&]() { + for (size_t i = 0; i < N_ADD_AFFINE; i++) { + G1.add(out_jac, p1_aff, p2_aff); + } + }); + + // 2) pure Jacobian -> affine + G1.add(tmp_jac, p1_aff, p2_aff); + double ms_to_affine = bench_ms([&]() { + for (size_t i = 0; i < N_TO_AFFINE; i++) { + G1.copy(out_aff, tmp_jac); + } + }); + + // 3) exact prepare-step shape: + // add(affine, affine) + copy(PointAffine <- Point) + G1PointAffine cur_aff; + G1.copy(cur_aff, p1_aff); + + double ms_build_step = bench_ms([&]() { + for (size_t i = 0; i < N_BUILD_STEP; i++) { + G1.add(tmp_jac, cur_aff, p1_aff); + G1.copy(cur_aff, tmp_jac); + } + }); + + ASSERT_FALSE(G1.isZero(out_aff)); + ASSERT_FALSE(G1.isZero(cur_aff)); + + std::cout << std::fixed << std::setprecision(3); + std::cout << "[perf][nogmp] G1.add affine+affine -> jac : " + << ms_add_affine << " ms (N=" << N_ADD_AFFINE + << ") => " << ns_per_op(ms_add_affine, N_ADD_AFFINE) << " ns/op\n"; + + std::cout << "[perf][nogmp] G1.copy jac -> affine : " + << ms_to_affine << " ms (N=" << N_TO_AFFINE + << ") => " << ns_per_op(ms_to_affine, N_TO_AFFINE) << " ns/op\n"; + + std::cout << "[perf][nogmp] build step (add_aff + toAff): " + << ms_build_step << " ms (N=" << N_BUILD_STEP + << ") => " << ns_per_op(ms_build_step, N_BUILD_STEP) << " ns/op\n"; +} + +TEST(altBn128Perf, prepare_breakdown_nogmp) { + const int NMExp = 40000; + + typedef mp_uint_t Scalar; + + Scalar *scalars = new Scalar[NMExp]; + G1PointAffine *bases = new G1PointAffine[NMExp]; + + double ms_scalars = bench_ms([&]() { + for (int i = 0; i < NMExp; i++) { + mp_uint_t x; + mp_set(x, (uint64_t)(i + 1)); + mp_copy(scalars[i], x); + } + }); + + double ms_bases = bench_ms([&]() { + for (int i = 0; i < NMExp; i++) { + if (i == 0) { + G1.copy(bases[0], G1.one()); + } else { + G1.add(bases[i], bases[i - 1], G1.one()); + } + } + }); + + ASSERT_FALSE(G1.isZero(bases[NMExp - 1])); + + std::cout << std::fixed << std::setprecision(3); + std::cout << "[perf][nogmp] prepare scalars only : " << ms_scalars << " ms (N=" << NMExp << ")\n"; + std::cout << "[perf][nogmp] prepare bases only : " << ms_bases << " ms (N=" << NMExp << ")\n"; + + delete[] bases; + delete[] scalars; +} } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} +} \ No newline at end of file diff --git a/c/curve.cpp b/c/curve.cpp index af35ebf..acf51eb 100644 --- a/c/curve.cpp +++ b/c/curve.cpp @@ -559,18 +559,100 @@ void Curve::copy(Point &r, PointAffine &a) { F.copy(r.zzz, F.one()); } +template +void Curve::batchToAffine(PointAffine *out, Point *in, size_t n) { + if (n == 0) return; + + typename BaseField::Element *prod = new typename BaseField::Element[n]; + typename BaseField::Element *prefix = new typename BaseField::Element[n]; + bool *is_nonzero = new bool[n]; + + typename BaseField::Element acc; + F.copy(acc, F.one()); + + for (size_t i = 0; i < n; i++) { + if (isZero(in[i])) { + is_nonzero[i] = false; + continue; + } + + is_nonzero[i] = true; + + // prod[i] = zz * zzz + F.mul(prod[i], in[i].zz, in[i].zzz); + + // prefix[i] = previous accumulated product + F.copy(prefix[i], acc); + + // acc *= prod[i] + F.mul(acc, acc, prod[i]); + } + + typename BaseField::Element acc_inv; + F.inv(acc_inv, acc); // single inversion for all points + + for (size_t k = n; k-- > 0;) { + if (!is_nonzero[k]) { + F.copy(out[k].x, F.zero()); + F.copy(out[k].y, F.zero()); + continue; + } + + typename BaseField::Element inv_prod; + typename BaseField::Element inv_zz; + typename BaseField::Element inv_zzz; + + // inv_prod = 1 / (zz * zzz) + F.mul(inv_prod, prefix[k], acc_inv); + + // acc_inv *= prod[k] for next iteration + F.mul(acc_inv, acc_inv, prod[k]); + + // inv_zz = zzz * inv_prod + // inv_zzz = zz * inv_prod + F.mul(inv_zz, in[k].zzz, inv_prod); + F.mul(inv_zzz, in[k].zz, inv_prod); + + F.mul(out[k].x, in[k].x, inv_zz); + F.mul(out[k].y, in[k].y, inv_zzz); + } + + delete[] prod; + delete[] prefix; + delete[] is_nonzero; +} + template void Curve::copy(PointAffine &r, Point &a) { #ifdef COUNT_OPS cntToAffine++; #endif // COUNT_OPS + if (isZero(a)) { F.copy(r.x, F.zero()); F.copy(r.y, F.zero()); return; } - F.div(r.x, a.x, a.zz); - F.div(r.y, a.y, a.zzz); + + typename BaseField::Element t; + typename BaseField::Element t_inv; + typename BaseField::Element inv_zz; + typename BaseField::Element inv_zzz; + + // t = zz * zzz = Z^5 + F.mul(t, a.zz, a.zzz); + + // t_inv = 1 / (zz * zzz) + F.inv(t_inv, t); + + // inv_zz = 1 / zz + // inv_zzz = 1 / zzz + F.mul(inv_zz, a.zzz, t_inv); + F.mul(inv_zzz, a.zz, t_inv); + + // affine coordinates + F.mul(r.x, a.x, inv_zz); + F.mul(r.y, a.y, inv_zzz); } template @@ -595,6 +677,61 @@ void Curve::neg(Point &r, PointAffine &a) { F.copy(r.zzz, F.one()); } +template +void Curve::batchNegToAffine(PointAffine *out, Point *in, size_t n) { + if (n == 0) return; + + typename BaseField::Element *prod = new typename BaseField::Element[n]; + typename BaseField::Element *prefix = new typename BaseField::Element[n]; + bool *is_nonzero = new bool[n]; + + typename BaseField::Element acc; + F.copy(acc, F.one()); + + for (size_t i = 0; i < n; i++) { + if (isZero(in[i])) { + is_nonzero[i] = false; + continue; + } + + is_nonzero[i] = true; + + F.mul(prod[i], in[i].zz, in[i].zzz); + F.copy(prefix[i], acc); + F.mul(acc, acc, prod[i]); + } + + typename BaseField::Element acc_inv; + F.inv(acc_inv, acc); // single inversion for all points + + for (size_t k = n; k-- > 0;) { + if (!is_nonzero[k]) { + F.copy(out[k].x, F.zero()); + F.copy(out[k].y, F.zero()); + continue; + } + + typename BaseField::Element inv_prod; + typename BaseField::Element inv_zz; + typename BaseField::Element inv_zzz; + typename BaseField::Element y_aff; + + F.mul(inv_prod, prefix[k], acc_inv); + F.mul(acc_inv, acc_inv, prod[k]); + + F.mul(inv_zz, in[k].zzz, inv_prod); + F.mul(inv_zzz, in[k].zz, inv_prod); + + F.mul(out[k].x, in[k].x, inv_zz); + F.mul(y_aff, in[k].y, inv_zzz); + F.neg(out[k].y, y_aff); + } + + delete[] prod; + delete[] prefix; + delete[] is_nonzero; +} + template void Curve::neg(PointAffine &r, Point &a) { #ifdef COUNT_OPS @@ -605,9 +742,28 @@ void Curve::neg(PointAffine &r, Point &a) { F.copy(r.y, F.zero()); return; } - F.div(r.x, a.x, a.zz); - F.div(r.y, a.y, a.zzz); - F.neg(r.y, r.y); + + typename BaseField::Element t; + typename BaseField::Element t_inv; + typename BaseField::Element inv_zz; + typename BaseField::Element inv_zzz; + typename BaseField::Element y_aff; + + // t = zz * zzz + F.mul(t, a.zz, a.zzz); + + // one inversion + F.inv(t_inv, t); + + // 1/zz and 1/zzz + F.mul(inv_zz, a.zzz, t_inv); + F.mul(inv_zzz, a.zz, t_inv); + + // x = X / zz + // y = -(Y / zzz) + F.mul(r.x, a.x, inv_zz); + F.mul(y_aff, a.y, inv_zzz); + F.neg(r.y, y_aff); } template diff --git a/c/curve.hpp b/c/curve.hpp index f6efb92..4bb6488 100644 --- a/c/curve.hpp +++ b/c/curve.hpp @@ -87,6 +87,7 @@ class Curve { void dbl(PointAffine &r, Point &a) { Point tmp; dbl(tmp, a); copy(r, tmp); } void dbl(PointAffine &r, PointAffine &a) { Point tmp; dbl(tmp, a); copy(r, tmp); } + void batchNegToAffine(PointAffine *out, Point *in, size_t n); void neg(Point &r, Point &a); void neg(PointAffine &r, PointAffine &a); @@ -103,6 +104,8 @@ class Curve { std::string toString(Point &r, uint32_t radix = 10); + void batchToAffine(PointAffine *out, Point *in, size_t n); + void copy(Point &r, Point &a); void copy(Point &r, PointAffine &a); void copy(PointAffine &r, Point &a); diff --git a/c/fft.cpp b/c/fft.cpp index c557ae0..f8d1c26 100644 --- a/c/fft.cpp +++ b/c/fft.cpp @@ -36,39 +36,54 @@ FFT::FFT(u_int64_t maxDomainSize, uint32_t _nThreads) u_int32_t domainPow = log2(maxDomainSize); - mpz_t m_qm1d2; - mpz_t m_q; - mpz_t m_nqr; - mpz_t m_aux; - mpz_init(m_qm1d2); - mpz_init(m_q); - mpz_init(m_nqr); - mpz_init(m_aux); - - f.toMpz(m_aux, f.negOne()); - - mpz_add_ui(m_q, m_aux, 1); - mpz_fdiv_q_2exp(m_qm1d2, m_aux, 1); - - mpz_set_ui(m_nqr, 2); - mpz_powm(m_aux, m_nqr, m_qm1d2, m_q); - while (mpz_cmp_ui(m_aux, 1) == 0) { - mpz_add_ui(m_nqr, m_nqr, 1); - mpz_powm(m_aux, m_nqr, m_qm1d2, m_q); + typedef uint64_t mp_uint_t[Field::N64]; + + mp_uint_t m_qm1d2; + mp_uint_t m_q; + mp_uint_t m_nqr; + mp_uint_t m_aux; + + // mpz_init(...) + mp_set(m_qm1d2, 0); + mp_set(m_q, 0); + mp_set(m_nqr, 0); + mp_set(m_aux, 0); + + // f.toMpz(m_aux, f.negOne()); + // mpz_add_ui(m_q, m_aux, 1); + // mpz_fdiv_q_2exp(m_qm1d2, m_aux, 1); + f.toMP(m_aux, f.negOne()); // generator должен дать toMp/fromMp (аналог toMpz/fromMpz) + mp_add(m_q, m_aux, 1); + mp_shr(m_qm1d2, m_aux, 1); + + // mpz_set_ui(m_nqr, 2); + // mpz_powm(m_aux, m_nqr, m_qm1d2, m_q); + // while (mpz_cmp_ui(m_aux, 1) == 0) { ... } + mp_set(m_nqr, 2); + + mp_uint_t one; + mp_set(one, 1); + + mp_pow_mod(m_aux, m_nqr, m_qm1d2, m_q); + while (mp_cmp(m_aux, one) == 0) { + mp_add(m_nqr, m_nqr, 1); + mp_pow_mod(m_aux, m_nqr, m_qm1d2, m_q); } - f.fromMpz(nqr, m_nqr); - - // std::cout << "nqr: " << f.toString(nqr) << std::endl; + // f.fromMpz(nqr, m_nqr); + f.fromMP(nqr, m_nqr); + // s = 1; + // mpz_set(m_aux, m_qm1d2); + // while ((!mpz_tstbit(m_aux, 0))&&(s::FFT(u_int64_t maxDomainSize, uint32_t _nThreads) f.copy(roots[0], f.one()); f.copy(powTwoInv[0], f.one()); - if (nRoots>1) { - mpz_powm(m_aux, m_nqr, m_aux, m_q); - f.fromMpz(roots[1], m_aux); - - mpz_set_ui(m_aux, 2); - mpz_invert(m_aux, m_aux, m_q); - f.fromMpz(powTwoInv[1], m_aux); + if (nRoots > 1) { + // mpz_powm(m_aux, m_nqr, m_aux, m_q); + // f.fromMpz(roots[1], m_aux); + mp_pow_mod(m_aux, m_nqr, m_aux, m_q); + f.fromMP(roots[1], m_aux); + + // mpz_set_ui(m_aux, 2); + // mpz_invert(m_aux, m_aux, m_q); + // f.fromMpz(powTwoInv[1], m_aux); + mp_set(m_aux, 2); + mp_inv_mod(m_aux, m_aux, m_q); + f.fromMP(powTwoInv[1], m_aux); } threadPool.parallelBlock([&] (uint64_t nThreads, uint64_t idThread) { @@ -93,13 +113,14 @@ FFT::FFT(u_int64_t maxDomainSize, uint32_t _nThreads) uint64_t increment = nRoots / nThreads; uint64_t start = idThread==0 ? 2 : idThread * increment; uint64_t end = idThread==nThreads-1 ? nRoots : (idThread+1) * increment; - if (end>start) { + if (end > start) { f.exp(roots[start], roots[1], (uint8_t *)(&start), sizeof(start)); } for (uint64_t i=start+1; i::FFT(u_int64_t maxDomainSize, uint32_t _nThreads) f.mul(powTwoInv[i], powTwoInv[i-1], powTwoInv[1]); } - mpz_clear(m_qm1d2); - mpz_clear(m_q); - mpz_clear(m_nqr); - mpz_clear(m_aux); + // mpz_clear(...) не нужен } template @@ -202,7 +220,7 @@ template void FFT::ifft(Element *a, u_int64_t n ) { fft(a, n); u_int64_t domainPow =log2(n); - u_int64_t nDiv2= n >> 1; + u_int64_t nDiv2= n >> 1; threadPool.parallelFor(1, nDiv2, [&] (int begin, int end, int numThread) { for (u_int64_t i=begin; i::printVector(Element *a, u_int64_t n ) { } cout << "]" << endl; } - diff --git a/c/fft.hpp b/c/fft.hpp index ab3c63b..3ffcf67 100644 --- a/c/fft.hpp +++ b/c/fft.hpp @@ -5,6 +5,7 @@ template class FFT { Field f; typedef typename Field::Element Element; + typedef uint64_t mp_uint_t[Field::N64]; u_int32_t s; Element nqr; diff --git a/c/wtns_utils.cpp b/c/wtns_utils.cpp index 2301c3a..a70bf07 100644 --- a/c/wtns_utils.cpp +++ b/c/wtns_utils.cpp @@ -2,26 +2,30 @@ namespace WtnsUtils { -Header::Header() { +Header::Header() + : n8(0), + nVars(0) +{ } -Header::~Header() { - mpz_clear(prime); -} +Header::~Header() = default; std::unique_ptr
loadHeader(BinFileUtils::BinFile *f) { - Header *h = new Header(); + std::unique_ptr
h(new Header()); + f->startReadSection(1); h->n8 = f->readU32LE(); - mpz_init(h->prime); - mpz_import(h->prime, h->n8, -1, 1, -1, 0, f->read(h->n8)); + { + const uint8_t* p = reinterpret_cast(f->read(h->n8)); + h->prime.assign(p, p + h->n8); + } h->nVars = f->readU32LE(); f->endReadSection(); - return std::unique_ptr
(h); + return h; } -} // NAMESPACE \ No newline at end of file +} // namespace WtnsUtils diff --git a/c/wtns_utils.hpp b/c/wtns_utils.hpp index 70aebc2..1766b2e 100644 --- a/c/wtns_utils.hpp +++ b/c/wtns_utils.hpp @@ -1,7 +1,9 @@ #ifndef WTNS_UTILS #define WTNS_UTILS -#include +#include +#include +#include #include "binfile_utils.hpp" @@ -10,7 +12,7 @@ namespace WtnsUtils { class Header { public: u_int32_t n8; - mpz_t prime; + std::vector prime; u_int32_t nVars; @@ -20,6 +22,6 @@ namespace WtnsUtils { std::unique_ptr
loadHeader(BinFileUtils::BinFile *f); -} +} // namespace WtnsUtils -#endif // ZKEY_UTILS_H \ No newline at end of file +#endif // WTNS_UTILS diff --git a/c/zkey_utils.cpp b/c/zkey_utils.cpp index 52a5629..f8ecbbf 100644 --- a/c/zkey_utils.cpp +++ b/c/zkey_utils.cpp @@ -1,17 +1,26 @@ - #include "zkey_utils.hpp" -namespace ZKeyUtils { - +#include -Header::Header() { -} +namespace ZKeyUtils { -Header::~Header() { - mpz_clear(qPrime); - mpz_clear(rPrime); +Header::Header() + : n8q(0), + n8r(0), + nVars(0), + nPublic(0), + domainSize(0), + nCoefs(0), + vk_alpha1(nullptr), + vk_beta1(nullptr), + vk_beta2(nullptr), + vk_gamma2(nullptr), + vk_delta1(nullptr), + vk_delta2(nullptr) +{ } +Header::~Header() = default; std::unique_ptr
loadHeader(BinFileUtils::BinFile *f) { auto h = new Header(); @@ -26,12 +35,16 @@ std::unique_ptr
loadHeader(BinFileUtils::BinFile *f) { f->startReadSection(2); h->n8q = f->readU32LE(); - mpz_init(h->qPrime); - mpz_import(h->qPrime, h->n8q, -1, 1, -1, 0, f->read(h->n8q)); + { + const uint8_t* p = reinterpret_cast(f->read(h->n8q)); + h->qPrime.assign(p, p + h->n8q); + } h->n8r = f->readU32LE(); - mpz_init(h->rPrime); - mpz_import(h->rPrime, h->n8r , -1, 1, -1, 0, f->read(h->n8r)); + { + const uint8_t* p = reinterpret_cast(f->read(h->n8r)); + h->rPrime.assign(p, p + h->n8r); + } h->nVars = f->readU32LE(); h->nPublic = f->readU32LE(); diff --git a/c/zkey_utils.hpp b/c/zkey_utils.hpp index 5bd5e67..f3503d0 100644 --- a/c/zkey_utils.hpp +++ b/c/zkey_utils.hpp @@ -1,8 +1,9 @@ #ifndef ZKEY_UTILS_H #define ZKEY_UTILS_H -#include #include +#include +#include #include "binfile_utils.hpp" @@ -13,9 +14,10 @@ namespace ZKeyUtils { public: u_int32_t n8q; - mpz_t qPrime; + std::vector qPrime; + u_int32_t n8r; - mpz_t rPrime; + std::vector rPrime; u_int32_t nVars; u_int32_t nPublic; diff --git a/package-lock.json b/package-lock.json index 91cd98e..606d3d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "chai": "^4.2.0", "eslint": "^6.8.0", "ffjavascript": "0.0.3", + "mocha": "^11.7.5", "tasksfile": "^5.1.0", "tmp-promise": "^2.0.2" } @@ -50,6 +51,109 @@ "js-tokens": "^4.0.0" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@pawelgalazka/cli": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@pawelgalazka/cli/-/cli-2.0.2.tgz", @@ -99,6 +203,17 @@ "node": ">=8.6.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -165,9 +280,10 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -235,6 +351,13 @@ "concat-map": "0.0.1" } }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -298,6 +421,22 @@ "node": "*" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -384,13 +523,21 @@ } }, "node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decamelize": { @@ -419,6 +566,16 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -431,6 +588,13 @@ "node": ">=6.0.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/ejs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.0.1.tgz", @@ -445,6 +609,16 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -700,6 +874,16 @@ "node": ">=8" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -720,6 +904,100 @@ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/foreground-child/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -805,6 +1083,16 @@ "node": ">=4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -997,18 +1285,67 @@ "node": ">=0.10.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1070,6 +1407,106 @@ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -1097,6 +1534,16 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", @@ -1110,16 +1557,347 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/mocha": { + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "node_modules/mocha/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mocha/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/mocha/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/mocha/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "node_modules/natural-compare": { @@ -1214,6 +1992,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1252,6 +2037,23 @@ "node": ">=4" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", @@ -1261,6 +2063,13 @@ "node": "*" } }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, "node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -1288,6 +2097,30 @@ "node": ">=6" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", @@ -1368,6 +2201,27 @@ "npm": ">=2.0.0" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -1383,6 +2237,16 @@ "semver": "bin/semver.js" } }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -1445,24 +2309,55 @@ "dev": true }, "node_modules/string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -1480,6 +2375,20 @@ "node": ">=6" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi/node_modules/ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", @@ -1490,12 +2399,16 @@ } }, "node_modules/strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/supports-color": { @@ -1729,6 +2642,13 @@ "node": ">=0.10.0" } }, + "node_modules/workerpool": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -1742,6 +2662,74 @@ "node": ">=8" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -1839,6 +2827,61 @@ "engines": { "node": ">=6" } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { @@ -1868,6 +2911,71 @@ "js-tokens": "^4.0.0" } }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "requires": { + "ansi-regex": "^6.2.2" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "@pawelgalazka/cli": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@pawelgalazka/cli/-/cli-2.0.2.tgz", @@ -1906,6 +3014,13 @@ "integrity": "sha512-MsNuS9M2vVbJNW3+YSiz9eF0/U2ZPlEEVC4ky8QJnxFlU4H7DZOH5A1hDQUfF5DV/pYwBD76dkF3+mrzZTJ3Tw==", "dev": true }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -1954,9 +3069,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "3.2.1", @@ -2009,6 +3124,12 @@ "concat-map": "0.0.1" } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2057,6 +3178,15 @@ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, + "chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "requires": { + "readdirp": "^4.0.1" + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -2135,12 +3265,12 @@ } }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "^2.1.3" } }, "decamelize": { @@ -2163,6 +3293,12 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2172,6 +3308,12 @@ "esutils": "^2.0.2" } }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "ejs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.0.1.tgz", @@ -2182,6 +3324,12 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -2378,6 +3526,12 @@ "path-exists": "^4.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -2395,6 +3549,65 @@ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, + "foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2456,6 +3669,12 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2605,18 +3824,46 @@ "is-extglob": "^2.1.1" } }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2669,6 +3916,73 @@ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -2690,6 +4004,12 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true + }, "mkdirp": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", @@ -2699,10 +4019,228 @@ "minimist": "^1.2.5" } }, + "mocha": { + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", + "dev": true, + "requires": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.2" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "mute-stream": { @@ -2782,6 +4320,12 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2808,12 +4352,28 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -2832,6 +4392,21 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", @@ -2891,6 +4466,12 @@ "tslib": "^1.9.0" } }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2903,6 +4484,15 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -2955,21 +4545,43 @@ "dev": true }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "dependencies": { "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" + } + } + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" } } } @@ -2991,10 +4603,19 @@ } } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "supports-color": { @@ -3185,6 +4806,12 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "workerpool": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "dev": true + }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -3227,6 +4854,52 @@ } } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3273,6 +4946,38 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index 76bbaf7..52ba831 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "chai": "^4.2.0", "eslint": "^6.8.0", "ffjavascript": "0.0.3", + "mocha": "^11.7.5", "tasksfile": "^5.1.0", "tmp-promise": "^2.0.2" }, diff --git a/src/armbuilder.js b/src/armbuilder.js index 57ad918..a981d7a 100644 --- a/src/armbuilder.js +++ b/src/armbuilder.js @@ -1,7 +1,7 @@ const bigInt = require("big-integer"); const assert = require("assert"); -module.exports.genFuncs = genFuncs +module.exports.genFuncs = genFuncs; class Reg { constructor(number) { @@ -211,7 +211,7 @@ class GenBase { if (size % 2) { this.op("ldr", saved[size-1], "[sp], #16"); - size--; + size--; } for (let i =size; i > 0; i -= 2) { @@ -336,7 +336,7 @@ class GenBase { class Gen_rawIsZero extends GenBase { constructor(width, space) { - super(width, space, "rawIsZero", 1, 16) + super(width, space, "rawIsZero", 1, 16); this.generate(); } @@ -363,7 +363,7 @@ class Gen_rawIsZero extends GenBase { } genChunk(width, i) { - let r = this.genStep(width, i * 4); + let r = this.genStep(width, i * 4); if (this.accum === undefined) { this.accum = r; @@ -466,7 +466,7 @@ class Gen_rawIsEq extends GenBase { this.op_empty(); } - genStep(width, i) { + genStep(width, i) { assert(width > 0); if (width === 1) { @@ -906,9 +906,9 @@ class Gen_rawNeg extends GenBase { this.genSubtraction(); if (this.hasSavedRegs()) - this.op("b", this.makeLabel("out")); + this.op("b", this.makeLabel("out")); else - this.op("ret"); + this.op("ret"); this.op_empty(); this.op_label(doneLabel); @@ -1010,7 +1010,7 @@ class Gen_rawNegLS extends GenBase { } if (this.width % 2) this.op_empty(); - this.op("cset", "x2", "cs"); + this.op("cset", "x2", "cc"); //sub fix } genSubtractionOpA() { @@ -1021,7 +1021,7 @@ class Gen_rawNegLS extends GenBase { } if (this.width % 2) this.op_empty(); - this.op("cset", "x3", "cs"); + this.op("cset", "x3", "cc"); //sub fix this.op("orr", "x3", "x3", "x2"); this.op_empty(); this.op("cbz", "x3", this.makeLabel("done")); @@ -1081,9 +1081,11 @@ class Gen_rawShr extends GenBase { genCalcJump() { if (this.width > 2) { this.op("lsr", "x2", "x2", "#6"); - this.op("adr", "x5", this.makeLabel("word_shift")); - this.op("ldr", "x5", "[x5, x2, lsl 3]"); - this.op("br", "x5"); + for (let i = 0; i < this.width - 1; i++) { + this.op("cmp", "x2", "#" + i); + this.op("b.eq", this.makeWordLabel(i)); + } + this.op("b", this.makeWordLabel(this.width - 1)); } else { this.op("tbnz", "x2", "6", this.makeLabel("word_shift_1")); @@ -1092,11 +1094,6 @@ class Gen_rawShr extends GenBase { } genJumpTable() { - this.op_label(this.makeLabel("word_shift")); - - for (let i = 0; i < this.width; i++) { - this.op(".quad", this.makeWordLabel(i)); - } } genShift() { @@ -1122,7 +1119,7 @@ class Gen_rawShr extends GenBase { if (!this.hasSavedRegs()) this.op("ret"); - this.op_empty(); + this.op_empty(); } genBitShift(wordShift) { @@ -1215,9 +1212,11 @@ class Gen_rawShl extends GenBase { genCalcJump() { if (this.width > 2) { this.op("lsr", "x2", "x2", "#6"); - this.op("adr", "x5", this.makeLabel("word_shift")); - this.op("ldr", "x5", "[x5, x2, lsl 3]"); - this.op("br", "x5"); + for (let i = 0; i < this.width - 1; i++) { + this.op("cmp", "x2", "#" + i); + this.op("b.eq", this.makeWordLabel(i)); + } + this.op("b", this.makeWordLabel(this.width - 1)); } else { this.op("tbnz", "x2", "6", this.makeLabel("word_shift_1")); @@ -1226,11 +1225,6 @@ class Gen_rawShl extends GenBase { } genJumpTable() { - this.op_label(this.makeLabel("word_shift")); - - for (let i = 0; i < this.width; i++) { - this.op(".quad", this.makeWordLabel(i)); - } } genShift() { @@ -1415,11 +1409,11 @@ class Gen_rawMul extends GenBase { let t1 = cyclicCopy(new RegVar(7, 5), this.width); for(i = 0; i < this.width; i++) { - let iAdd = (i === this.width - 1) ? "adc" : "adcs"; + let iAdd = (i === this.width - 1) ? "adc" : "adcs"; - if (!this.canOptimizeConsensys) { + if (!this.canOptimizeConsensys) { iAdd = (i) ? "adcs" : "adds"; - } + } if (!this.isShort) this.genLoadVarWord(this.b1, i, 2); this.op("umulh", t1[i], this.b1[i], ra); diff --git a/src/buildzqfield.js b/src/buildzqfield.js index 6fbc2e0..a44adeb 100755 --- a/src/buildzqfield.js +++ b/src/buildzqfield.js @@ -53,8 +53,10 @@ async function buildField(q, name) { const generic_cpp = await renderFile(path.join(__dirname, "fr_generic.cpp.ejs"), builder); const raw_generic_cpp = await renderFile(path.join(__dirname, "fr_raw_generic.cpp.ejs"), builder); const raw_arm64_s = await renderFile(path.join(__dirname, "fr_raw_arm64.s.ejs"), builder); + const mp_hpp = await renderFile(path.join(__dirname, "mp.hpp.ejs"), {n64: builder.n64}); + const mp_cpp = await renderFile(path.join(__dirname, "mp.cpp.ejs"), {n64: builder.n64}); - return {asm: asm, hpp: hpp, cpp: cpp, element_hpp: element_hpp, generic_cpp: generic_cpp, raw_generic_cpp: raw_generic_cpp, raw_arm64_s: raw_arm64_s}; + return {n64: builder.n64, asm: asm, hpp: hpp, cpp: cpp, element_hpp: element_hpp, generic_cpp: generic_cpp, raw_generic_cpp: raw_generic_cpp, raw_arm64_s: raw_arm64_s, mp_hpp: mp_hpp, mp_cpp: mp_cpp}; } if (runningAsScript) { @@ -85,6 +87,8 @@ if (runningAsScript) { fs.writeFileSync(cGenericFileName, res.generic_cpp, "utf8"); fs.writeFileSync(cRawGenericFileName, res.raw_generic_cpp, "utf8"); fs.writeFileSync(sRawArm64FileName, res.raw_arm64_s, "utf8"); + fs.writeFileSync("mp.hpp", res.mp_hpp, "utf8"); + fs.writeFileSync("mp.cpp", res.mp_cpp, "utf8"); }); } else { diff --git a/src/fr.cpp.ejs b/src/fr.cpp.ejs index 9d3f1e2..b739126 100644 --- a/src/fr.cpp.ejs +++ b/src/fr.cpp.ejs @@ -1,159 +1,85 @@ #include "<%=name.toLowerCase()+".hpp"%>" -#include -#include -#include -#include +#include "mp.hpp" +#include #include +#include +#include - -static mpz_t q; -static mpz_t zero; -static mpz_t one; -static mpz_t mask; -static size_t nBits; -static bool initialized = false; - - -void <%=name%>_toMpz(mpz_t r, P<%=name%>Element pE) { +void <%=name%>_toMP(mp_uint_t out, P<%=name%>Element pE) { <%=name%>Element tmp; <%=name%>_toNormal(&tmp, pE); if (!(tmp.type & <%=name%>_LONG)) { - mpz_set_si(r, tmp.shortVal); - if (tmp.shortVal<0) { - mpz_add(r, r, q); - } + mp_set_mod(out, tmp.shortVal, <%=name%>_q.longVal); } else { - mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)tmp.longVal); + mp_copy(out, tmp.longVal); } } -void <%=name%>_fromMpz(P<%=name%>Element pE, mpz_t v) { - if (mpz_fits_sint_p(v)) { +void <%=name%>_fromMP(P<%=name%>Element pE, const mp_uint_t v) { + if (mp_fits_int32(v)) { pE->type = <%=name%>_SHORT; - pE->shortVal = mpz_get_si(v); + pE->shortVal = mp_get_int32(v); } else { pE->type = <%=name%>_LONG; - for (int i=0; i<<%=name%>_N64; i++) pE->longVal[i] = 0; - mpz_export((void *)(pE->longVal), NULL, -1, 8, -1, 0, v); + mp_copy(pE->longVal, v); } } - -bool <%=name%>_init() { - if (initialized) return false; - initialized = true; - mpz_init(q); - mpz_import(q, <%=name%>_N64, -1, 8, -1, 0, (const void *)<%=name%>_q.longVal); - mpz_init_set_ui(zero, 0); - mpz_init_set_ui(one, 1); - nBits = mpz_sizeinbase (q, 2); - mpz_init(mask); - mpz_mul_2exp(mask, one, nBits); - mpz_sub(mask, mask, one); - return true; -} - -void <%=name%>_str2element(P<%=name%>Element pE, char const *s) { - mpz_t mr; - mpz_init_set_str(mr, s, 10); - mpz_fdiv_r(mr, mr, q); - <%=name%>_fromMpz(pE, mr); - mpz_clear(mr); +void <%=name%>_str2element(P<%=name%>Element pE, char const* s, int base) { + mp_uint_t v; + if (!mp_set_mod(v, s, base, <%=name%>_q.longVal)) { + mp_set(v, 0); + } + <%=name%>_fromMP(pE, v); } -char *<%=name%>_element2str(P<%=name%>Element pE) { - <%=name%>Element tmp; - mpz_t r; - if (!(pE->type & <%=name%>_LONG)) { - if (pE->shortVal>=0) { - char *r = new char[32]; - sprintf(r, "%d", pE->shortVal); - return r; - } else { - mpz_init_set_si(r, pE->shortVal); - mpz_add(r, r, q); - } - } else { - <%=name%>_toNormal(&tmp, pE); - mpz_init(r); - mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)tmp.longVal); - } - char *res = mpz_get_str (0, 10, r); - mpz_clear(r); - return res; +std::string <%=name%>_element2str(P<%=name%>Element pE, uint32_t base) { + mp_uint_t v; + <%=name%>_toMP(v, pE); + return mp_get_str(v, base); } void <%=name%>_idiv(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - // char *s1 = mpz_get_str (0, 10, ma); - // printf("s1 %s\n", s1); - <%=name%>_toMpz(mb, b); - // char *s2 = mpz_get_str (0, 10, mb); - // printf("s2 %s\n", s2); - mpz_fdiv_q(mr, ma, mb); - // char *sr = mpz_get_str (0, 10, mr); - // printf("r %s\n", sr); - <%=name%>_fromMpz(r, mr); - - mpz_clear(ma); - mpz_clear(mb); - mpz_clear(mr); + mp_uint_t ma, mb; + <%=name%>_toMP(ma, a); + <%=name%>_toMP(mb, b); + + mp_uint_t q, rem; + mp_div(q, rem, ma, mb); + <%=name%>_fromMP(r, q); } void <%=name%>_mod(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - <%=name%>_toMpz(mb, b); - mpz_fdiv_r(mr, ma, mb); - <%=name%>_fromMpz(r, mr); - - mpz_clear(ma); - mpz_clear(mb); - mpz_clear(mr); + mp_uint_t ma, mb; + <%=name%>_toMP(ma, a); + <%=name%>_toMP(mb, b); + + mp_uint_t q, rem; + mp_div(q, rem, ma, mb); + <%=name%>_fromMP(r, rem); } void <%=name%>_pow(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - <%=name%>_toMpz(mb, b); - mpz_powm(mr, ma, mb, q); - <%=name%>_fromMpz(r, mr); - - mpz_clear(ma); - mpz_clear(mb); - mpz_clear(mr); + mp_uint_t mb; + <%=name%>_toMP(mb, b); + + mp_uint_t base; + <%=name%>_toMP(base, a); + + mp_uint_t res; + mp_pow_mod(res, base, mb, <%=name%>_q.longVal); + + <%=name%>_fromMP(r, res); } void <%=name%>_inv(P<%=name%>Element r, P<%=name%>Element a) { - mpz_t ma; - mpz_t mr; - mpz_init(ma); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - mpz_invert(mr, ma, q); - <%=name%>_fromMpz(r, mr); - mpz_clear(ma); - mpz_clear(mr); + mp_uint_t base; + <%=name%>_toMP(base, a); + + mp_uint_t res; + mp_inv_mod(res, base, <%=name%>_q.longVal); + + <%=name%>_fromMP(r, res); } void <%=name%>_div(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { @@ -163,7 +89,7 @@ void <%=name%>_div(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b } void <%=name%>_fail() { - assert(false); + throw std::runtime_error("<%=name%> error"); } void <%=name%>_longErr() { @@ -171,104 +97,70 @@ void <%=name%>_longErr() { } Raw<%=name%>::Raw<%=name%>() { - <%=name%>_init(); set(fZero, 0); set(fOne, 1); neg(fNegOne, fOne); } -Raw<%=name%>::~Raw<%=name%>() { -} +Raw<%=name%>::~Raw<%=name%>() {} -void Raw<%=name%>::fromString(Element &r, const std::string &s, uint32_t radix) { - mpz_t mr; - mpz_init_set_str(mr, s.c_str(), radix); - mpz_fdiv_r(mr, mr, q); - for (int i=0; i<<%=name%>_N64; i++) r.v[i] = 0; - mpz_export((void *)(r.v), NULL, -1, 8, -1, 0, mr); - <%=name%>_rawToMontgomery(r.v,r.v); - mpz_clear(mr); +void Raw<%=name%>::fromString(Element& r, const std::string& s, uint32_t radix) { + if (!mp_set_mod(r.v, s.c_str(), radix, <%=name%>_q.longVal)) { + mp_set(r.v, 0); + } + <%=name%>_rawToMontgomery(r.v, r.v); } -void Raw<%=name%>::fromUI(Element &r, unsigned long int v) { - mpz_t mr; - mpz_init(mr); - mpz_set_ui(mr, v); - for (int i=0; i<<%=name%>_N64; i++) r.v[i] = 0; - mpz_export((void *)(r.v), NULL, -1, 8, -1, 0, mr); - <%=name%>_rawToMontgomery(r.v,r.v); - mpz_clear(mr); +void Raw<%=name%>::fromUI(Element& r, unsigned long int v) { + mp_set(r.v, v); + <%=name%>_rawToMontgomery(r.v, r.v); } Raw<%=name%>::Element Raw<%=name%>::set(int value) { - Element r; - set(r, value); - return r; + Element r; + set(r, value); + return r; } -void Raw<%=name%>::set(Element &r, int value) { - mpz_t mr; - mpz_init(mr); - mpz_set_si(mr, value); - if (value < 0) { - mpz_add(mr, mr, q); - } - - mpz_export((void *)(r.v), NULL, -1, 8, -1, 0, mr); - - for (int i=0; i<<%=name%>_N64; i++) r.v[i] = 0; - mpz_export((void *)(r.v), NULL, -1, 8, -1, 0, mr); - <%=name%>_rawToMontgomery(r.v,r.v); - mpz_clear(mr); +void Raw<%=name%>::set(Element& r, int value) { + mp_set_mod(r.v, value, <%=name%>_q.longVal); + <%=name%>_rawToMontgomery(r.v, r.v); } -std::string Raw<%=name%>::toString(const Element &a, uint32_t radix) { +std::string Raw<%=name%>::toString(const Element& a, uint32_t radix) { Element tmp; - mpz_t r; <%=name%>_rawFromMontgomery(tmp.v, a.v); - mpz_init(r); - mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)(tmp.v)); - char *res = mpz_get_str (0, radix, r); - mpz_clear(r); - std::string resS(res); - free(res); - return resS; + return mp_get_str(tmp.v, radix); } -void Raw<%=name%>::inv(Element &r, const Element &a) { - mpz_t mr; - mpz_init(mr); - mpz_import(mr, <%=name%>_N64, -1, 8, -1, 0, (const void *)(a.v)); - mpz_invert(mr, mr, q); - - - for (int i=0; i<<%=name%>_N64; i++) r.v[i] = 0; - mpz_export((void *)(r.v), NULL, -1, 8, -1, 0, mr); - - <%=name%>_rawMMul(r.v, r.v,<%=name%>_R3.longVal); - mpz_clear(mr); +void Raw<%=name%>::inv(Element& r, const Element& a) { + Element t; + <%=name%>_rawFromMontgomery(t.v, a.v); + mp_inv_mod(r.v, t.v, <%=name%>_q.longVal); + <%=name%>_rawMMul(r.v, r.v, <%=name%>_R2.longVal); } -void Raw<%=name%>::div(Element &r, const Element &a, const Element &b) { +void Raw<%=name%>::div(Element& r, const Element& a, const Element& b) { Element tmp; inv(tmp, b); mul(r, a, tmp); } -#define BIT_IS_SET(s, p) (s[p>>3] & (1 << (p & 0x7))) -void Raw<%=name%>::exp(Element &r, const Element &base, uint8_t* scalar, unsigned int scalarSize) { +#define BIT_IS_SET(s, p) (s[(p)>>3] & (1 << ((p) & 0x7))) +void Raw<%=name%>::exp(Element& r, const Element& base, uint8_t* scalar, unsigned int scalarSize) { bool oneFound = false; Element copyBase; copy(copyBase, base); - for (int i=scalarSize*8-1; i>=0; i--) { + + for (int i = (int)scalarSize * 8 - 1; i >= 0; i--) { if (!oneFound) { - if ( !BIT_IS_SET(scalar, i) ) continue; + if (!BIT_IS_SET(scalar, i)) continue; copy(r, copyBase); oneFound = true; continue; } square(r, r); - if ( BIT_IS_SET(scalar, i) ) { + if (BIT_IS_SET(scalar, i)) { mul(r, r, copyBase); } } @@ -277,48 +169,37 @@ void Raw<%=name%>::exp(Element &r, const Element &base, uint8_t* scalar, unsigne } } -void Raw<%=name%>::toMpz(mpz_t r, const Element &a) { - Element tmp; - <%=name%>_rawFromMontgomery(tmp.v, a.v); - mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)tmp.v); +void Raw<%=name%>::toMP(mp_uint_t r, const Element &a) { + <%=name%>RawElement tmp; + <%=name%>_rawFromMontgomery(tmp, a.v); + mp_copy(r, tmp); } -void Raw<%=name%>::fromMpz(Element &r, const mpz_t a) { - for (int i=0; i<<%=name%>_N64; i++) r.v[i] = 0; - mpz_export((void *)(r.v), NULL, -1, 8, -1, 0, a); - <%=name%>_rawToMontgomery(r.v, r.v); +void Raw<%=name%>::fromMP(Element &a, const mp_uint_t r) { + mp_copy(a.v, r); + <%=name%>_rawToMontgomery(a.v, a.v); } -int Raw<%=name%>::toRprBE(const Element &element, uint8_t *data, int bytes) -{ - if (bytes < <%=name%>_N64 * 8) { - return -(<%=name%>_N64 * 8); - } - - mpz_t r; - mpz_init(r); +int Raw<%=name%>::toRprBE(const Element& element, uint8_t* data, int bytes) { + const int need = <%=name%>_N64 * 8; + if (bytes < need) return -need; - toMpz(r, element); - - mpz_export(data, NULL, 1, bytes, 1, 0, r); + mp_uint_t v; + toMP(v, element); + mp_export_be(data, v); - return <%=name%>_N64 * 8; + return need; } -int Raw<%=name%>::fromRprBE(Element &element, const uint8_t *data, int bytes) -{ - if (bytes < <%=name%>_N64 * 8) { - return -(<%=name%>_N64* 8); - } - mpz_t r; - mpz_init(r); - - mpz_import(r, <%=name%>_N64 * 8, 0, 1, 0, 0, data); - fromMpz(element, r); - return <%=name%>_N64 * 8; -} +int Raw<%=name%>::fromRprBE(Element& element, const uint8_t* data, int bytes) { + const int need = <%=name%>_N64 * 8; + if (bytes < need) return -need; -static bool init = <%=name%>_init(); + mp_uint_t v; + mp_import_be(v, data); + fromMP(element, v); -Raw<%=name%> Raw<%=name%>::field; + return need; +} +Raw<%=name%> Raw<%=name%>::field; \ No newline at end of file diff --git a/src/fr.hpp.ejs b/src/fr.hpp.ejs index 1bbe388..27cbca3 100644 --- a/src/fr.hpp.ejs +++ b/src/fr.hpp.ejs @@ -4,7 +4,11 @@ #include "<%=name.toLowerCase()%>_element.hpp" #include #include -#include +#include "mp.hpp" + +#ifdef __APPLE__ +#include // typedef unsigned int uint; +#endif // __APPLE__ extern <%=name%>Element <%=name%>_q; extern <%=name%>Element <%=name%>_R2; @@ -51,10 +55,10 @@ extern "C" void <%=name%>_rawNeg(<%=name%>RawElement pRawResult, const <%=name%> extern "C" void <%=name%>_rawMMul(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB); extern "C" void <%=name%>_rawMSquare(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); extern "C" void <%=name%>_rawMMul1(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, uint64_t pRawB); -extern "C" void <%=name%>_rawToMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); -extern "C" void <%=name%>_rawFromMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); -extern "C" int <%=name%>_rawIsEq(<%=name%>RawElement const pRawA, const <%=name%>RawElement pRawB); -extern "C" int <%=name%>_rawIsZero(const <%=name%>RawElement pRawB); +extern "C" void <%=name%>_rawToMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement &pRawA); +extern "C" void <%=name%>_rawFromMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement &pRawA); +extern "C" int <%=name%>_rawIsEq(const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB); +extern "C" int <%=name%>_rawIsZero(const <%=name%>RawElement pRawB); extern "C" void <%=name%>_rawShl(<%=name%>RawElement r, <%=name%>RawElement a, uint64_t b); extern "C" void <%=name%>_rawShr(<%=name%>RawElement r, <%=name%>RawElement a, uint64_t b); @@ -99,8 +103,8 @@ extern "C" void <%=name%>_rawNeg(<%=name%>RawElement pRawResult, const <%=name%> extern "C" void <%=name%>_rawMMul(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB); void <%=name%>_rawMSquare(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); extern "C" void <%=name%>_rawMMul1(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, uint64_t pRawB); - void <%=name%>_rawToMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); -extern "C" void <%=name%>_rawFromMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); + void <%=name%>_rawToMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement &pRawA); +extern "C" void <%=name%>_rawFromMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement &pRawA); extern "C" int <%=name%>_rawIsEq(const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB); extern "C" int <%=name%>_rawIsZero(const <%=name%>RawElement pRawB); void <%=name%>_rawZero(<%=name%>RawElement pRawResult); @@ -118,8 +122,8 @@ extern "C" void <%=name%>_rawShr(<%=name%>RawElement r, <%=name%>RawElement a, u extern "C" void <%=name%>_rawNot(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA); extern "C" void <%=name%>_rawSubRegular(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA, <%=name%>RawElement pRawB); - void <%=name%>_fail(); - void <%=name%>_longErr(); +void <%=name%>_fail(); +void <%=name%>_longErr(); #endif @@ -163,8 +167,8 @@ void <%=name%>_rawNeg(<%=name%>RawElement pRawResult, const <%=name%>RawElement void <%=name%>_rawMMul(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB); void <%=name%>_rawMSquare(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); void <%=name%>_rawMMul1(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, uint64_t pRawB); -void <%=name%>_rawToMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); -void <%=name%>_rawFromMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA); +void <%=name%>_rawToMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement &pRawA); +void <%=name%>_rawFromMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement &pRawA); int <%=name%>_rawIsEq(const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB); int <%=name%>_rawIsZero(const <%=name%>RawElement pRawB); void <%=name%>_rawZero(<%=name%>RawElement pRawResult); @@ -187,10 +191,11 @@ void <%=name%>_longErr(); #endif -// Pending functions to convert -void <%=name%>_str2element(P<%=name%>Element pE, char const*s); -char *<%=name%>_element2str(P<%=name%>Element pE); +void <%=name%>_toMP(mp_uint_t out, P<%=name%>Element a); +void <%=name%>_fromMP(P<%=name%>Element out, const mp_uint_t v); +void <%=name%>_str2element(P<%=name%>Element pE, char const* s, int base); +std::string <%=name%>_element2str(P<%=name%>Element pE, uint32_t base = 10); void <%=name%>_idiv(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); void <%=name%>_mod(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); void <%=name%>_inv(P<%=name%>Element r, P<%=name%>Element a); @@ -203,7 +208,6 @@ public: const static int N64 = <%=name%>_N64; const static int MaxBits = <%= q.bitLength() %>; - struct Element { <%=name%>RawElement v; }; @@ -214,65 +218,65 @@ private: Element fNegOne; public: - Raw<%=name%>(); ~Raw<%=name%>(); - const Element &zero() { return fZero; } - const Element &one() { return fOne; } - const Element &negOne() { return fNegOne; } + const Element &zero() { return fZero; }; + const Element &one() { return fOne; }; + const Element &negOne() { return fNegOne; }; Element set(int value); void set(Element &r, int value); void fromString(Element &r, const std::string &n, uint32_t radix = 10); std::string toString(const Element &a, uint32_t radix = 10); - void inline copy(Element &r, const Element &a) { <%=name%>_rawCopy(r.v, a.v); } - void inline swap(Element &a, Element &b) { <%=name%>_rawSwap(a.v, b.v); } - void inline add(Element &r, const Element &a, const Element &b) { <%=name%>_rawAdd(r.v, a.v, b.v); } - void inline sub(Element &r, const Element &a, const Element &b) { <%=name%>_rawSub(r.v, a.v, b.v); } - void inline mul(Element &r, const Element &a, const Element &b) { <%=name%>_rawMMul(r.v, a.v, b.v); } + void inline copy(Element &r, const Element &a) { <%=name%>_rawCopy(r.v, a.v); }; + void inline swap(Element &a, Element &b) { <%=name%>_rawSwap(a.v, b.v); }; + void inline add(Element &r, const Element &a, const Element &b) { <%=name%>_rawAdd(r.v, a.v, b.v); }; + void inline sub(Element &r, const Element &a, const Element &b) { <%=name%>_rawSub(r.v, a.v, b.v); }; + void inline mul(Element &r, const Element &a, const Element &b) { <%=name%>_rawMMul(r.v, a.v, b.v); }; - Element inline add(const Element &a, const Element &b) { Element r; <%=name%>_rawAdd(r.v, a.v, b.v); return r;} - Element inline sub(const Element &a, const Element &b) { Element r; <%=name%>_rawSub(r.v, a.v, b.v); return r;} - Element inline mul(const Element &a, const Element &b) { Element r; <%=name%>_rawMMul(r.v, a.v, b.v); return r;} + Element inline add(const Element &a, const Element &b) { Element r; <%=name%>_rawAdd(r.v, a.v, b.v); return r;}; + Element inline sub(const Element &a, const Element &b) { Element r; <%=name%>_rawSub(r.v, a.v, b.v); return r;}; + Element inline mul(const Element &a, const Element &b) { Element r; <%=name%>_rawMMul(r.v, a.v, b.v); return r;}; - Element inline neg(const Element &a) { Element r; <%=name%>_rawNeg(r.v, a.v); return r; } - Element inline square(const Element &a) { Element r; <%=name%>_rawMSquare(r.v, a.v); return r; } + Element inline neg(const Element &a) { Element r; <%=name%>_rawNeg(r.v, a.v); return r; }; + Element inline square(const Element &a) { Element r; <%=name%>_rawMSquare(r.v, a.v); return r; }; - Element inline add(int a, const Element &b) { return add(set(a), b);} - Element inline sub(int a, const Element &b) { return sub(set(a), b);} - Element inline mul(int a, const Element &b) { return mul(set(a), b);} + Element inline add(int a, const Element &b) { return add(set(a), b);}; + Element inline sub(int a, const Element &b) { return sub(set(a), b);}; + Element inline mul(int a, const Element &b) { return mul(set(a), b);}; - Element inline add(const Element &a, int b) { return add(a, set(b));} - Element inline sub(const Element &a, int b) { return sub(a, set(b));} - Element inline mul(const Element &a, int b) { return mul(a, set(b));} + Element inline add(const Element &a, int b) { return add(a, set(b));}; + Element inline sub(const Element &a, int b) { return sub(a, set(b));}; + Element inline mul(const Element &a, int b) { return mul(a, set(b));}; - void inline mul1(Element &r, const Element &a, uint64_t b) { <%=name%>_rawMMul1(r.v, a.v, b); } - void inline neg(Element &r, const Element &a) { <%=name%>_rawNeg(r.v, a.v); } - void inline square(Element &r, const Element &a) { <%=name%>_rawMSquare(r.v, a.v); } + void inline mul1(Element &r, const Element &a, uint64_t b) { <%=name%>_rawMMul1(r.v, a.v, b); }; + void inline neg(Element &r, const Element &a) { <%=name%>_rawNeg(r.v, a.v); }; + void inline square(Element &r, const Element &a) { <%=name%>_rawMSquare(r.v, a.v); }; void inv(Element &r, const Element &a); void div(Element &r, const Element &a, const Element &b); void exp(Element &r, const Element &base, uint8_t* scalar, unsigned int scalarSize); - void inline toMontgomery(Element &r, const Element &a) { <%=name%>_rawToMontgomery(r.v, a.v); } - void inline fromMontgomery(Element &r, const Element &a) { <%=name%>_rawFromMontgomery(r.v, a.v); } - int inline eq(const Element &a, const Element &b) { return <%=name%>_rawIsEq(a.v, b.v); } - int inline isZero(const Element &a) { return <%=name%>_rawIsZero(a.v); } + void inline toMontgomery(Element &r, const Element &a) { <%=name%>_rawToMontgomery(r.v, a.v); }; + void inline fromMontgomery(Element &r, const Element &a) { <%=name%>_rawFromMontgomery(r.v, a.v); }; + int inline eq(const Element &a, const Element &b) { return <%=name%>_rawIsEq(a.v, b.v); }; + int inline isZero(const Element &a) { return <%=name%>_rawIsZero(a.v); }; - void toMpz(mpz_t r, const Element &a); - void fromMpz(Element &a, const mpz_t r); + void toMP(mp_uint_t r, const Element &a); + void fromMP(Element &a, const mp_uint_t r); int toRprBE(const Element &element, uint8_t *data, int bytes); int fromRprBE(Element &element, const uint8_t *data, int bytes); - int bytes ( void ) { return <%=name%>_N64 * 8; } - + int bytes ( void ) { return <%=name%>_N64 * 8; }; void fromUI(Element &r, unsigned long int v); static Raw<%=name%> field; - }; #endif // __<%=name.toUpperCase()%>_H + + + diff --git a/src/fr_generic.cpp.ejs b/src/fr_generic.cpp.ejs index 2cd5a6d..8d63429 100644 --- a/src/fr_generic.cpp.ejs +++ b/src/fr_generic.cpp.ejs @@ -9,7 +9,17 @@ static <%=name%>RawElement half = {<%= constantElement(q.shiftRight(1)) %>}; static <%=name%>RawElement zero = {0}; +static <%=name%>RawElement <%=name%>_rawR2 = {<%= constantElement(bigInt.one.shiftLeft(n64*64*2).mod(q)) %>}; +void <%=name%>_rawMSquare(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA) +{ + <%=name%>_rawMMul(pRawResult, pRawA, pRawA); +} + +void <%=name%>_rawToMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement &pRawA) +{ + <%=name%>_rawMMul(pRawResult, pRawA, <%=name%>_rawR2); +} void <%=name%>_copy(P<%=name%>Element r, const P<%=name%>Element a) { @@ -271,6 +281,7 @@ void <%=name%>_mul(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b } } + void <%=name%>_toLongNormal(P<%=name%>Element r, P<%=name%>Element a) { if (a->type & <%=name%>_LONG) diff --git a/src/fr_raw_generic.cpp.ejs b/src/fr_raw_generic.cpp.ejs index e13bbb1..6c51e01 100644 --- a/src/fr_raw_generic.cpp.ejs +++ b/src/fr_raw_generic.cpp.ejs @@ -1,362 +1,367 @@ -#include "<%=name.toLowerCase()+"_element.hpp"%>" -#include +#include "<%=name.toLowerCase()%>_element.hpp" +#include "mp.hpp" #include static uint64_t <%=name%>_rawq[] = {<%= constantElement(q) %>, 0}; -static <%=name%>RawElement <%=name%>_rawR2 = {<%= constantElement(bigInt.one.shiftLeft(n64*64*2).mod(q)) %>}; -static uint64_t <%=name%>_np = 0x<%= (bigInt.one.shiftLeft(64)).minus(q.modInv(bigInt.one.shiftLeft(64))).toString(16) %>; +static const uint64_t <%=name%>_np = 0x<%= (bigInt.one.shiftLeft(64)).minus(q.modInv(bigInt.one.shiftLeft(64))).toString(16) %>ULL; static uint64_t lboMask = 0x<%= bigInt("10000000000000000",16).shiftRight(n64*64 - q.bitLength()).minus(bigInt.one).toString(16) %>; -static <%=name%>RawElement zero = {0}; void <%=name%>_rawAdd(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB) { - uint64_t carry = mpn_add_n(pRawResult, pRawA, pRawB, <%=name%>_N64); + uint64_t carry = mp_add(pRawResult, pRawA, pRawB); - if(carry || mpn_cmp(pRawResult, <%=name%>_rawq, <%=name%>_N64) >= 0) + if (carry || mp_cmp(pRawResult, <%=name%>_rawq) >= 0) { - mpn_sub_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawAddLS(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA, uint64_t rawB) { - uint64_t carry = mpn_add_1(pRawResult, pRawA, <%=name%>_N64, rawB); + uint64_t carry = mp_add(pRawResult, pRawA, rawB); - if(carry || mpn_cmp(pRawResult, <%=name%>_rawq, <%=name%>_N64) >= 0) + if (carry || mp_cmp(pRawResult, <%=name%>_rawq) >= 0) { - mpn_sub_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawSub(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB) { - uint64_t carry = mpn_sub_n(pRawResult, pRawA, pRawB, <%=name%>_N64); + uint64_t carry = mp_sub(pRawResult, pRawA, pRawB); - if(carry) + if (carry) { - mpn_add_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_add(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawSubRegular(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA, <%=name%>RawElement pRawB) { - mpn_sub_n(pRawResult, pRawA, pRawB, <%=name%>_N64); + mp_sub(pRawResult, pRawA, pRawB); } void <%=name%>_rawSubSL(<%=name%>RawElement pRawResult, uint64_t rawA, <%=name%>RawElement pRawB) { - <%=name%>RawElement pRawA = {rawA}; + <%=name%>RawElement pRawA = {0}; + pRawA[0] = rawA; - uint64_t carry = mpn_sub_n(pRawResult, pRawA, pRawB, <%=name%>_N64); + uint64_t carry = mp_sub(pRawResult, pRawA, pRawB); - if(carry) + if (carry) { - mpn_add_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_add(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawSubLS(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA, uint64_t rawB) { - uint64_t carry = mpn_sub_1(pRawResult, pRawA, <%=name%>_N64, rawB); + uint64_t carry = mp_sub(pRawResult, pRawA, rawB); - if(carry) + if (carry) { - mpn_add_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_add(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawNeg(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA) { - if (mpn_cmp(pRawA, zero, <%=name%>_N64) != 0) + if (!mp_is_zero(pRawA)) { - mpn_sub_n(pRawResult, <%=name%>_rawq, pRawA, <%=name%>_N64); + mp_sub(pRawResult, <%=name%>_rawq, pRawA); } else { - mpn_copyi(pRawResult, zero, <%=name%>_N64); + mp_set(pRawResult, 0); } } -// Substracts a long element and a short element form 0 +// Subtracts a long element and a short element from 0 void <%=name%>_rawNegLS(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA, uint64_t rawB) { - uint64_t carry1 = mpn_sub_1(pRawResult, <%=name%>_rawq, <%=name%>_N64, rawB); - uint64_t carry2 = mpn_sub_n(pRawResult, pRawResult, pRawA, <%=name%>_N64); + uint64_t carry1 = mp_sub(pRawResult, <%=name%>_rawq, rawB); + uint64_t carry2 = mp_sub(pRawResult, pRawResult, pRawA); if (carry1 || carry2) { - mpn_add_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_add(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawCopy(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA) { - memcpy(pRawResult, pRawA, sizeof(<%=name%>RawElement)); +<% for (let i=0; i + pRawResult[<%=i%>] = pRawA[<%=i%>]; +<% } %> } int <%=name%>_rawIsEq(const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB) { - return mpn_cmp(pRawA, pRawB, <%=name%>_N64) == 0; + return mp_cmp(pRawA, pRawB) == 0; } void <%=name%>_rawMMul(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, const <%=name%>RawElement pRawB) { - const mp_size_t N = <%=name%>_N64+1; - const uint64_t *mq = <%=name%>_rawq; + constexpr size_t N = <%=name%>_N64 + 1; + const uint64_t *mq = <%=name%>_rawq; + + uint64_t np0; <% if (!canOptimizeConsensys) { %> - uint64_t c = 0; -<% } -%> - uint64_t np0; -<% for (let i=0; i - uint64_t product<%=i%>[N] = {0}; + uint64_t c = 0; <% } %> - product0[N-1] = mpn_mul_1(product0, pRawB, <%=name%>_N64, pRawA[0]); -<% if (!canOptimizeConsensys) { -%> -<% for (let i=0; i - np0 = <%=name%>_np * product<%=i%>[0]; - product<%=i+1%>[N-1] += mpn_addmul_1(product<%=i%>, mq, N, np0); - - product<%=i+1%>[N-1] += mpn_addmul_1(product<%=i+1%>, pRawB, <%=name%>_N64, pRawA[<%=i+1%>]); -<% if (i == n64-2) { -%> - c = mpn_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%>+1, N-1); -<% } else { -%> - product<%=i+2%>[N-1] = mpn_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%>+1, N-1); -<% } -%> + +<% for (let i=0; i + uint64_t product<%=i%>[N] = {0}; <% } %> -<% } else { -%> + + product0[<%=n64%>] = mp_mul(product0, pRawB, pRawA[0]); + <% for (let i=0; i np0 = <%=name%>_np * product<%=i%>[0]; - product<%=i+1%>[1] = mpn_addmul_1(product<%=i%>, mq, N, np0); - - product<%=i+1%>[N-1] = mpn_addmul_1(product<%=i+1%>, pRawB, <%=name%>_N64, pRawA[<%=i+1%>]); - mpn_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%>+1, N-1); +<% if (!canOptimizeConsensys) { %> + c += mp_addmul(product<%=i%>, mq, N, np0); +<% } else { %> + product<%=i+1%>[1] = mp_addmul(product<%=i%>, mq, N, np0); <% } %> -<% } -%> - np0 = <%=name%>_np * product<%=n64-1%>[0]; -<% if (!canOptimizeConsensys) { -%> - c += mpn_addmul_1(product<%=n64-1%>, mq, N, np0); - mpn_copyi(pRawResult, product<%=n64-1%>+1, <%=name%>_N64); + product<%=i+1%>[<%=n64%>] = mp_addmul(product<%=i+1%>, pRawB, <%=name%>_N64, pRawA[<%=i+1%>]); +<% if (!canOptimizeConsensys) { %> + product<%=i+1%>[<%=n64%>] += c; + c = mp_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%> + 1, N - 1); +<% } else { %> + mp_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%> + 1, N - 1); +<% } %> +<% } %> - if (c || mpn_cmp(pRawResult, mq, <%=name%>_N64) >= 0) -<% } else { -%> - mpn_addmul_1(product<%=n64-1%>, mq, N, np0); + np0 = <%=name%>_np * product<%=n64-1%>[0]; +<% if (!canOptimizeConsensys) { %> + c += mp_addmul(product<%=n64-1%>, mq, N, np0); +<% } else { %> + mp_addmul(product<%=n64-1%>, mq, N, np0); +<% } %> - mpn_copyi(pRawResult, product<%=n64-1%>+1, <%=name%>_N64); + mp_copy(pRawResult, product<%=n64-1%> + 1); - if (mpn_cmp(pRawResult, mq, <%=name%>_N64) >= 0) -<% } -%> +<% if (!canOptimizeConsensys) { %> + if (c || mp_cmp(pRawResult, mq) >= 0) +<% } else { %> + if (mp_cmp(pRawResult, mq) >= 0) +<% } %> { - mpn_sub_n(pRawResult, pRawResult, mq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, mq); } } -void <%=name%>_rawMSquare(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA) -{ - <%=name%>_rawMMul(pRawResult, pRawA, pRawA); -} - void <%=name%>_rawMMul1(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA, uint64_t pRawB) { - const mp_size_t N = <%=name%>_N64+1; - const uint64_t *mq = <%=name%>_rawq; + constexpr size_t N = <%=name%>_N64 + 1; + const uint64_t *mq = <%=name%>_rawq; + + uint64_t np0; <% if (!canOptimizeConsensys) { %> - uint64_t c = 0; -<% } -%> - uint64_t np0; -<% for (let i=0; i - uint64_t product<%=i%>[N] = {0}; + uint64_t c = 0; <% } %> - product0[N-1] = mpn_mul_1(product0, pRawA, <%=name%>_N64, pRawB); + +<% for (let i=0; i + uint64_t product<%=i%>[N] = {0}; +<% } %> + + product0[<%=n64%>] = mp_mul(product0, pRawA, pRawB); + <% for (let i=0; i np0 = <%=name%>_np * product<%=i%>[0]; -<% if (!canOptimizeConsensys) { -%> - product<%=i+1%>[N-1] = mpn_addmul_1(product<%=i%>, mq, N, np0); -<% } else { -%> - product<%=i+1%>[1] = mpn_addmul_1(product<%=i%>, mq, N, np0); -<% } -%> - mpn_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%>+1, N-1); +<% if (!canOptimizeConsensys) { %> + c += mp_addmul(product<%=i%>, mq, N, np0); +<% } else { %> + product<%=i+1%>[1] = mp_addmul(product<%=i%>, mq, N, np0); <% } %> - np0 = <%=name%>_np * product<%=n64-1%>[0]; -<% if (!canOptimizeConsensys) { -%> - c = mpn_addmul_1(product<%=n64-1%>, mq, N, np0); - mpn_copyi(pRawResult, product<%=n64-1%>+1, <%=name%>_N64); +<% if (!canOptimizeConsensys) { %> + product<%=i+1%>[<%=n64%>] += c; + c = mp_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%> + 1, N - 1); +<% } else { %> + mp_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%> + 1, N - 1); +<% } %> +<% } %> - if (c || mpn_cmp(pRawResult, mq, <%=name%>_N64) >= 0) -<% } else { -%> - mpn_addmul_1(product<%=n64-1%>, mq, N, np0); + np0 = <%=name%>_np * product<%=n64-1%>[0]; +<% if (!canOptimizeConsensys) { %> + c += mp_addmul(product<%=n64-1%>, mq, N, np0); +<% } else { %> + mp_addmul(product<%=n64-1%>, mq, N, np0); +<% } %> - mpn_copyi(pRawResult, product<%=n64-1%>+1, <%=name%>_N64); + mp_copy(pRawResult, product<%=n64-1%> + 1); - if (mpn_cmp(pRawResult, mq, <%=name%>_N64) >= 0) -<% } -%> +<% if (!canOptimizeConsensys) { %> + if (c || mp_cmp(pRawResult, mq) >= 0) +<% } else { %> + if (mp_cmp(pRawResult, mq) >= 0) +<% } %> { - mpn_sub_n(pRawResult, pRawResult, mq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, mq); } } -void <%=name%>_rawToMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA) +void <%=name%>_rawFromMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement &pRawA) { - <%=name%>_rawMMul(pRawResult, pRawA, <%=name%>_rawR2); -} + constexpr size_t N = <%=name%>_N64 + 1; + const uint64_t *mq = <%=name%>_rawq; -void <%=name%>_rawFromMontgomery(<%=name%>RawElement pRawResult, const <%=name%>RawElement pRawA) -{ - const mp_size_t N = <%=name%>_N64+1; - const uint64_t *mq = <%=name%>_rawq; + uint64_t np0; <% if (!canOptimizeConsensys) { %> - uint64_t c = 0; -<% } -%> - uint64_t np0; - uint64_t product0[N]; -<% for (let i=1; i - uint64_t product<%=i%>[N] = {0}; + uint64_t c = 0; <% } %> - mpn_copyi(product0, pRawA, <%=name%>_N64); product0[N-1] = 0; + + uint64_t product0[N]; +<% for (let i=1; i + uint64_t product<%=i%>[N] = {0}; +<% } %> + + mp_copy(product0, pRawA); + product0[<%=n64%>] = 0; + <% for (let i=0; i np0 = <%=name%>_np * product<%=i%>[0]; -<% if (!canOptimizeConsensys) { -%> - product<%=i+1%>[N-1] = mpn_addmul_1(product<%=i%>, mq, N, np0); -<% } else { -%> - product<%=i+1%>[1] = mpn_addmul_1(product<%=i%>, mq, N, np0); -<% } -%> - mpn_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%>+1, N-1); +<% if (!canOptimizeConsensys) { %> + c += mp_addmul(product<%=i%>, mq, N, np0); +<% } else { %> + product<%=i+1%>[1] = mp_addmul(product<%=i%>, mq, N, np0); <% } %> - np0 = <%=name%>_np * product<%=n64-1%>[0]; -<% if (!canOptimizeConsensys) { -%> - c = mpn_addmul_1(product<%=n64-1%>, mq, N, np0); - mpn_copyi(pRawResult, product<%=n64-1%>+1, <%=name%>_N64); +<% if (!canOptimizeConsensys) { %> + product<%=i+1%>[<%=n64%>] += c; + c = mp_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%> + 1, N - 1); +<% } else { %> + mp_add(product<%=i+1%>, product<%=i+1%>, N, product<%=i%> + 1, N - 1); +<% } %> +<% } %> - if (c || mpn_cmp(pRawResult, mq, <%=name%>_N64) >= 0) -<% } else { -%> - mpn_addmul_1(product<%=n64-1%>, mq, N, np0); + np0 = <%=name%>_np * product<%=n64-1%>[0]; +<% if (!canOptimizeConsensys) { %> + c += mp_addmul(product<%=n64-1%>, mq, N, np0); +<% } else { %> + mp_addmul(product<%=n64-1%>, mq, N, np0); +<% } %> - mpn_copyi(pRawResult, product<%=n64-1%>+1, <%=name%>_N64); + mp_copy(pRawResult, product<%=n64-1%> + 1); - if (mpn_cmp(pRawResult, mq, <%=name%>_N64) >= 0) -<% } -%> +<% if (!canOptimizeConsensys) { %> + if (c || mp_cmp(pRawResult, mq) >= 0) +<% } else { %> + if (mp_cmp(pRawResult, mq) >= 0) +<% } %> { - mpn_sub_n(pRawResult, pRawResult, mq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, mq); } } int <%=name%>_rawIsZero(const <%=name%>RawElement rawA) { - return mpn_zero_p(rawA, <%=name%>_N64) ? 1 : 0; + return mp_is_zero(rawA) ? 1 : 0; } int <%=name%>_rawCmp(<%=name%>RawElement pRawA, <%=name%>RawElement pRawB) { - return mpn_cmp(pRawA, pRawB, <%=name%>_N64); + return mp_cmp(pRawA, pRawB); } void <%=name%>_rawSwap(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA) { <%=name%>RawElement temp; - <%=name%>_rawCopy(temp, pRawResult); - <%=name%>_rawCopy(pRawResult, pRawA); - <%=name%>_rawCopy(pRawA, temp); +<% for (let i=0; i + temp[<%=i%>] = pRawResult[<%=i%>]; +<% } %> + +<% for (let i=0; i + pRawResult[<%=i%>] = pRawA[<%=i%>]; +<% } %> + +<% for (let i=0; i + pRawA[<%=i%>] = temp[<%=i%>]; +<% } %> } void <%=name%>_rawCopyS2L(<%=name%>RawElement pRawResult, int64_t val) { pRawResult[0] = val; <% for (let i=1; i - pRawResult[<%= i %>] = 0;<% } %> + pRawResult[<%=i%>] = 0; +<% } %> - if (val < 0) { + if (val < 0) + { <% for (let i=1; i - pRawResult[<%= i %>] = -1;<% } %> + pRawResult[<%=i%>] = (uint64_t)-1; +<% } %> - mpn_add_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_add(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawAnd(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA, <%=name%>RawElement pRawB) { - mpn_and_n(pRawResult, pRawA, pRawB, <%=name%>_N64); + mp_and(pRawResult, pRawA, pRawB); - pRawResult[<%= n64 - 1 %>] &= lboMask; + pRawResult[<%=n64-1%>] &= lboMask; - if (mpn_cmp(pRawResult, <%=name%>_rawq, <%=name%>_N64) >= 0) + if (mp_cmp(pRawResult, <%=name%>_rawq) >= 0) { - mpn_sub_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawOr(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA, <%=name%>RawElement pRawB) { - mpn_ior_n(pRawResult, pRawA, pRawB, <%=name%>_N64); + mp_or(pRawResult, pRawA, pRawB); - pRawResult[<%= n64 - 1 %>] &= lboMask; + pRawResult[<%=n64-1%>] &= lboMask; - if (mpn_cmp(pRawResult, <%=name%>_rawq, <%=name%>_N64) >= 0) + if (mp_cmp(pRawResult, <%=name%>_rawq) >= 0) { - mpn_sub_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawXor(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA, <%=name%>RawElement pRawB) { - mpn_xor_n(pRawResult, pRawA, pRawB, <%=name%>_N64); + mp_xor(pRawResult, pRawA, pRawB); - pRawResult[<%= n64 - 1 %>] &= lboMask; + pRawResult[<%=n64-1%>] &= lboMask; - if (mpn_cmp(pRawResult, <%=name%>_rawq, <%=name%>_N64) >= 0) + if (mp_cmp(pRawResult, <%=name%>_rawq) >= 0) { - mpn_sub_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, <%=name%>_rawq); } } void <%=name%>_rawShl(<%=name%>RawElement r, <%=name%>RawElement a, uint64_t b) { - uint64_t bit_shift = b % 64; - uint64_t word_shift = b / 64; - uint64_t word_count = <%=name%>_N64 - word_shift; + mp_shl(r, a, (uint32_t)b); - mpn_copyi(r + word_shift, a, word_count); - std::memset(r, 0, word_shift * sizeof(uint64_t)); + r[<%=n64-1%>] &= lboMask; - if (bit_shift) + if (mp_cmp(r, <%=name%>_rawq) >= 0) { - mpn_lshift(r, r, <%=name%>_N64, bit_shift); - } - - r[<%= n64 - 1 %>] &= lboMask; - - if (mpn_cmp(r, <%=name%>_rawq, <%=name%>_N64) >= 0) - { - mpn_sub_n(r, r, <%=name%>_rawq, <%=name%>_N64); + mp_sub(r, r, <%=name%>_rawq); } } void <%=name%>_rawShr(<%=name%>RawElement r, <%=name%>RawElement a, uint64_t b) { - const uint64_t bit_shift = b % 64; - const uint64_t word_shift = b / 64; - const uint64_t word_count = <%=name%>_N64 - word_shift; - - mpn_copyi(r, a + word_shift, word_count); - std::memset(r + word_count, 0, word_shift * sizeof(uint64_t)); - - if (bit_shift) - { - mpn_rshift(r, r, <%=name%>_N64, bit_shift); - } + mp_shr(r, a, (uint32_t)b); } void <%=name%>_rawNot(<%=name%>RawElement pRawResult, <%=name%>RawElement pRawA) { - mpn_com(pRawResult, pRawA, <%=name%>_N64); + mp_not(pRawResult, pRawA); - pRawResult[<%= n64 - 1 %>] &= lboMask; + pRawResult[<%=n64-1%>] &= lboMask; - if (mpn_cmp(pRawResult, <%=name%>_rawq, <%=name%>_N64) >= 0) + if (mp_cmp(pRawResult, <%=name%>_rawq) >= 0) { - mpn_sub_n(pRawResult, pRawResult, <%=name%>_rawq, <%=name%>_N64); + mp_sub(pRawResult, pRawResult, <%=name%>_rawq); } } diff --git a/src/mp.cpp.ejs b/src/mp.cpp.ejs new file mode 100644 index 0000000..8e8812e --- /dev/null +++ b/src/mp.cpp.ejs @@ -0,0 +1,2798 @@ +#include "mp.hpp" + +#include +#include +#include +#include +#include +#include +#include + +static inline uint64_t add_carry(uint64_t *out, uint64_t a, uint64_t b, uint64_t c) { +#if defined(__clang__) || defined(__GNUC__) + uint64_t t; + unsigned c1 = __builtin_add_overflow(a, b, &t); + unsigned c2 = __builtin_add_overflow(t, c, &t); + *out = t; + return (c1 | c2); +#else + uint64_t t0 = a + b; + uint64_t carry1 = (t0 < a); + uint64_t t1 = t0 + c; + uint64_t carry2 = (t1 < t0); + *out = t1; + return carry1 | carry2; +#endif +} + +static inline uint64_t sub_borrow(uint64_t *out, uint64_t a, uint64_t b, uint64_t c) { +#if defined(__clang__) || defined(__GNUC__) + uint64_t t; + unsigned b1 = __builtin_sub_overflow(a, b, &t); + unsigned b2 = __builtin_sub_overflow(t, c, &t); + *out = t; + return (b1 | b2); +#else + uint64_t t0 = a - b; + uint64_t borrow1 = (a < b); + uint64_t t1 = t0 - c; + uint64_t borrow2 = (t0 < c); + *out = t1; + return borrow1 | borrow2; +#endif +} + +void mp_set(uint64_t *r, uint64_t a) { +#if MP_N64 == 4 + r[0] = a; + r[1] = 0; + r[2] = 0; + r[3] = 0; +#else + r[0] = a; + for (int i = 1; i < MP_N64; i++) r[i] = 0; +#endif +} + +bool mp_is_zero(const uint64_t *a) { +#if MP_N64 == 4 + return (a[0] | a[1] | a[2] | a[3]) == 0; +#else + uint64_t acc = 0; + for (int i = 0; i < MP_N64; ++i) + acc |= a[i]; + return acc == 0; +#endif +} + +uint64_t mp_add(uint64_t *r, const uint64_t *a, const uint64_t *b) { +#if MP_N64 == 4 + uint64_t c = 0; + c = add_carry(&r[0], a[0], b[0], c); + c = add_carry(&r[1], a[1], b[1], c); + c = add_carry(&r[2], a[2], b[2], c); + c = add_carry(&r[3], a[3], b[3], c); + return c; +#else + uint64_t c = 0; + + for (int i = 0; i < MP_N64; ++i) { + c = add_carry(&r[i], a[i], b[i], c); + } + + return c; +#endif +} + +uint64_t mp_add(uint64_t *r, const uint64_t *a, uint64_t b) { +#if MP_N64 == 4 + uint64_t c = 0; + c = add_carry(&r[0], a[0], b, c); + c = add_carry(&r[1], a[1], 0, c); + c = add_carry(&r[2], a[2], 0, c); + c = add_carry(&r[3], a[3], 0, c); + return c; +#else + uint64_t c = add_carry(&r[0], a[0], b, 0); + + for (int i = 1; i < MP_N64; ++i) { + c = add_carry(&r[i], a[i], 0, c); + } + + return c; +#endif +} + +uint64_t mp_sub(uint64_t *r, const uint64_t *a, const uint64_t *b) { +#if MP_N64 == 4 + uint64_t br = 0; + br = sub_borrow(&r[0], a[0], b[0], br); + br = sub_borrow(&r[1], a[1], b[1], br); + br = sub_borrow(&r[2], a[2], b[2], br); + br = sub_borrow(&r[3], a[3], b[3], br); + return br; +#else + uint64_t br = 0; + + for (int i = 0; i < MP_N64; ++i) { + br = sub_borrow(&r[i], a[i], b[i], br); + } + + return br; +#endif +} + +uint64_t mp_sub(uint64_t *r, const uint64_t *a, uint64_t b) { +#if MP_N64 == 4 + uint64_t br = 0; + br = sub_borrow(&r[0], a[0], b, br); + br = sub_borrow(&r[1], a[1], 0, br); + br = sub_borrow(&r[2], a[2], 0, br); + br = sub_borrow(&r[3], a[3], 0, br); + return br; +#else + uint64_t br = sub_borrow(&r[0], a[0], b, 0); + + for (int i = 1; i < MP_N64; ++i) { + br = sub_borrow(&r[i], a[i], 0, br); + } + + return br; +#endif +} + +static inline uint64_t load_be64(const uint8_t *p) { + uint64_t x; + std::memcpy(&x, p, sizeof(x)); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return __builtin_bswap64(x); +#else + return x; +#endif +} + +static inline void store_be64(uint8_t *p, uint64_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + x = __builtin_bswap64(x); +#endif + std::memcpy(p, &x, sizeof(x)); +} + +void mp_import_be(uint64_t *r, const uint8_t *a) { +#if MP_N64 == 4 + r[3] = load_be64(a + 0); + r[2] = load_be64(a + 8); + r[1] = load_be64(a + 16); + r[0] = load_be64(a + 24); +#else + auto *dst = reinterpret_cast(r); + const size_t nbytes = MP_N64 * sizeof(uint64_t); + + for (size_t i = 0; i < nbytes; ++i) { + dst[i] = a[nbytes - 1 - i]; + } +#endif +} + +void mp_export_be(uint8_t *r, const uint64_t *a) { +#if MP_N64 == 4 + store_be64(r + 0, a[3]); + store_be64(r + 8, a[2]); + store_be64(r + 16, a[1]); + store_be64(r + 24, a[0]); +#else + const auto *p = reinterpret_cast(a); + const size_t nbytes = MP_N64 * sizeof(uint64_t); + + for (size_t i = 0; i < nbytes; ++i) { + r[i] = p[nbytes - 1 - i]; + } +#endif +} + +enum class MpHexParseStatus { + Ok, + Invalid, + Overflow +}; + +alignas(64) static constexpr int8_t MP_HEX_DIGIT_TABLE[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static inline int mp_hex_digit(unsigned char c) { + return (int)MP_HEX_DIGIT_TABLE[c]; +} + +static inline bool mp_parse_hex64_exact_u256(uint64_t *r, const char *p) { + uint64_t r3 = 0; + uint64_t r2 = 0; + uint64_t r1 = 0; + uint64_t r0 = 0; + + for (int i = 0; i < 16; ++i) { + const int d = mp_hex_digit((unsigned char)p[i]); + if (d < 0) return false; + r3 = (r3 << 4) | (uint64_t)d; + } + + for (int i = 16; i < 32; ++i) { + const int d = mp_hex_digit((unsigned char)p[i]); + if (d < 0) return false; + r2 = (r2 << 4) | (uint64_t)d; + } + + for (int i = 32; i < 48; ++i) { + const int d = mp_hex_digit((unsigned char)p[i]); + if (d < 0) return false; + r1 = (r1 << 4) | (uint64_t)d; + } + + for (int i = 48; i < 64; ++i) { + const int d = mp_hex_digit((unsigned char)p[i]); + if (d < 0) return false; + r0 = (r0 << 4) | (uint64_t)d; + } + + r[3] = r3; + r[2] = r2; + r[1] = r1; + r[0] = r0; + return true; +} + +static inline bool mp_parse_hex_chunk_u64( + uint64_t *out, + const char *begin, + const char *end +) { + uint64_t x = 0; + + for (const char *p = begin; p != end; ++p) { + const int d = mp_hex_digit((unsigned char)*p); + if (d < 0) { + return false; + } + + x = (x << 4) | (uint64_t)d; + } + + *out = x; + return true; +} + +static MpHexParseStatus mp_parse_hex_u256( + uint64_t *r, + const char *str, + bool allow_neg, + bool *neg_out +) { + mp_zero(r); + + while (*str && std::isspace((unsigned char)*str)) { + ++str; + } + + bool neg = false; + + if (*str == '+') { + ++str; + } else if (*str == '-') { + if (!allow_neg) { + return MpHexParseStatus::Invalid; + } + + neg = true; + ++str; + } + +#if MP_N64 == 4 + { + const char *p = str; + + size_t len = 0; + while (len <= 64u) { + const unsigned char c = (unsigned char)p[len]; + + if (c == '\0' || std::isspace(c)) { + break; + } + + ++len; + } + + if (len == 64u) { + const char *tail = p + 64; + + while (*tail && std::isspace((unsigned char)*tail)) { + ++tail; + } + + if (*tail == '\0') { + if (mp_parse_hex64_exact_u256(r, p)) { + if (neg_out) { + *neg_out = neg; + } + + return MpHexParseStatus::Ok; + } + } + } + } +#endif + + const char *digits = str; + const char *end = str; + + while (*end && !std::isspace((unsigned char)*end)) { + ++end; + } + + if (end == digits) { + return MpHexParseStatus::Invalid; + } + + const char *tail = end; + while (*tail && std::isspace((unsigned char)*tail)) { + ++tail; + } + + if (*tail != '\0') { + return MpHexParseStatus::Invalid; + } + + uint64_t tmp[MP_N64] = {}; + size_t pos = (size_t)(end - digits); + + for (int limb = 0; limb < MP_N64 && pos > 0; ++limb) { + const size_t chunk_len = pos > 16u ? 16u : pos; + + const char *chunk_begin = digits + pos - chunk_len; + const char *chunk_end = digits + pos; + + if (!mp_parse_hex_chunk_u64(&tmp[limb], chunk_begin, chunk_end)) { + return MpHexParseStatus::Invalid; + } + + pos -= chunk_len; + } + + bool overflow = false; + + while (pos > 0) { + const int d = mp_hex_digit((unsigned char)digits[--pos]); + + if (d < 0) { + return MpHexParseStatus::Invalid; + } + + if (d != 0) { + overflow = true; + } + } + + for (int i = 0; i < MP_N64; ++i) { + r[i] = tmp[i]; + } + + if (neg_out) { + *neg_out = neg; + } + + return overflow ? MpHexParseStatus::Overflow : MpHexParseStatus::Ok; +} + +bool mp_set(uint64_t *r, const char *str, uint32_t base) { + if (base == 0u) base = 10u; + if (base < 2u || base > 16u) return false; + + if (base == 16u) { + MpHexParseStatus st = mp_parse_hex_u256(r, str, false, nullptr); + return st == MpHexParseStatus::Ok; + } + + mp_zero(r); + + while (*str && std::isspace((unsigned char)*str)) str++; + if (*str == '+') str++; + if (*str == '-') return false; + + bool any = false; + + for (; *str; ++str) { + if (std::isspace((unsigned char)*str)) break; + + const unsigned char uc = (unsigned char)*str; + uint32_t digit; + if (uc >= (unsigned char)'0' && uc <= (unsigned char)'9') { + digit = (uint32_t)(uc - (unsigned char)'0'); + } else if (uc >= (unsigned char)'a' && uc <= (unsigned char)'f') { + digit = (uint32_t)(uc - (unsigned char)'a') + 10u; + } else if (uc >= (unsigned char)'A' && uc <= (unsigned char)'F') { + digit = (uint32_t)(uc - (unsigned char)'A') + 10u; + } else { + return false; + } + if (digit >= base) return false; + + if (mp_mul(r, r, base) != 0) return false; + if (mp_add(r, r, digit) != 0) return false; + any = true; + } + + if (!any) return false; + while (*str && std::isspace((unsigned char)*str)) str++; + return *str == '\0'; +} + +static inline uint32_t mp_div(uint64_t *q, const uint64_t *a, uint32_t base) { +#if defined(__SIZEOF_INT128__) + uint64_t rem = 0; + + for (int i = MP_N64 - 1; i >= 0; i--) { + __uint128_t cur = (((__uint128_t)rem) << 2*MP_N) | (__uint128_t)a[i]; + q[i] = (uint64_t)(cur / base); + rem = (uint64_t)(cur % base); + } + return (uint32_t)rem; +#else + // long division in base 2^32: numerator = rem*2^64 + a[i] + // rem < base <= 16 => safe in uint32_t + uint32_t rem = 0; + for (int i = MP_N64 - 1; i >= 0; --i) { + uint32_t hi = (uint32_t)(a[i] >> MP_N); + uint32_t lo = (uint32_t)(a[i] & 0xFFFFFFFFu); + + uint64_t cur = ((uint64_t)rem << MP_N) | (uint64_t)hi; + uint32_t qhi = (uint32_t)(cur / base); + rem = (uint32_t)(cur % base); + + cur = ((uint64_t)rem << MP_N) | (uint64_t)lo; + uint32_t qlo = (uint32_t)(cur / base); + rem = (uint32_t)(cur % base); + + q[i] = ((uint64_t)qhi << MP_N) | (uint64_t)qlo; + } + return rem; +#endif +} + +#if defined(__SIZEOF_INT128__) +static inline uint64_t mp_div_u64_base(uint64_t *q, const uint64_t *a, uint64_t base) { + __uint128_t rem = 0; + + for (int i = MP_N64 - 1; i >= 0; --i) { + __uint128_t cur = (rem << 64) | (__uint128_t)a[i]; + q[i] = (uint64_t)(cur / base); + rem = cur % base; + } + + return (uint64_t)rem; +} +#endif + +static inline void mp_append_dec_u64(std::string &out, uint64_t v) { + char buf[20]; + int pos = 20; + + do { + const uint64_t q = v / 10u; + buf[--pos] = (char)('0' + (v - q * 10u)); + v = q; + } while (v != 0); + + out.append(buf + pos, 20 - pos); +} + +static inline void mp_append_dec_padded_9(std::string &out, uint32_t v) { + char buf[9]; + + for (int i = 8; i >= 0; --i) { + const uint32_t q = v / 10u; + buf[i] = (char)('0' + (v - q * 10u)); + v = q; + } + + out.append(buf, 9); +} + +#if defined(__SIZEOF_INT128__) +static inline void mp_append_dec_padded_19(std::string &out, uint64_t v) { + char buf[19]; + + for (int i = 18; i >= 0; --i) { + const uint64_t q = v / 10u; + buf[i] = (char)('0' + (v - q * 10u)); + v = q; + } + + out.append(buf, 19); +} +#endif + +static constexpr char MP_DEC_PAIR_TABLE[] = + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899"; + +static inline char *mp_write_dec_u64_back(char *p, uint64_t v) { + while (v >= 100u) { + const uint64_t q = v / 100u; + const unsigned r = (unsigned)(v - q * 100u); + + p -= 2; + p[0] = MP_DEC_PAIR_TABLE[2u * r + 0u]; + p[1] = MP_DEC_PAIR_TABLE[2u * r + 1u]; + + v = q; + } + + if (v >= 10u) { + const unsigned r = (unsigned)v; + + p -= 2; + p[0] = MP_DEC_PAIR_TABLE[2u * r + 0u]; + p[1] = MP_DEC_PAIR_TABLE[2u * r + 1u]; + } else { + *--p = (char)('0' + v); + } + + return p; +} + +static inline char *mp_write_dec_19_back(char *p, uint64_t v) { + for (int i = 0; i < 9; ++i) { + const uint64_t q = v / 100u; + const unsigned r = (unsigned)(v - q * 100u); + + p -= 2; + p[0] = MP_DEC_PAIR_TABLE[2u * r + 0u]; + p[1] = MP_DEC_PAIR_TABLE[2u * r + 1u]; + + v = q; + } + + *--p = (char)('0' + v); + + return p; +} + +static inline char *mp_write_dec_9_back(char *p, uint32_t v) { + for (int i = 0; i < 4; ++i) { + const uint32_t q = v / 100u; + const unsigned r = (unsigned)(v - q * 100u); + + p -= 2; + p[0] = MP_DEC_PAIR_TABLE[2u * r + 0u]; + p[1] = MP_DEC_PAIR_TABLE[2u * r + 1u]; + + v = q; + } + + *--p = (char)('0' + v); + + return p; +} + +static inline void mp_store_hex16(char *out, uint64_t x) { + static constexpr char hex[] = "0123456789abcdef"; + + out[0] = hex[(x >> 60) & 0xFu]; + out[1] = hex[(x >> 56) & 0xFu]; + out[2] = hex[(x >> 52) & 0xFu]; + out[3] = hex[(x >> 48) & 0xFu]; + out[4] = hex[(x >> 44) & 0xFu]; + out[5] = hex[(x >> 40) & 0xFu]; + out[6] = hex[(x >> 36) & 0xFu]; + out[7] = hex[(x >> 32) & 0xFu]; + out[8] = hex[(x >> 28) & 0xFu]; + out[9] = hex[(x >> 24) & 0xFu]; + out[10] = hex[(x >> 20) & 0xFu]; + out[11] = hex[(x >> 16) & 0xFu]; + out[12] = hex[(x >> 12) & 0xFu]; + out[13] = hex[(x >> 8) & 0xFu]; + out[14] = hex[(x >> 4) & 0xFu]; + out[15] = hex[x & 0xFu]; +} + +std::string mp_get_str(const uint64_t *a, uint32_t base) { + if (base == 0u) base = 10u; + if (base < 2u || base > 16u) return {}; + + if (mp_is_zero(a)) return {"0"}; + + if (base == 16u) { +#if MP_N64 == 4 + char buf[64]; + + mp_store_hex16(buf + 0, a[3]); + mp_store_hex16(buf + 16, a[2]); + mp_store_hex16(buf + 32, a[1]); + mp_store_hex16(buf + 48, a[0]); + + size_t first = 0; + while (first < 63 && buf[first] == '0') { + ++first; + } + + return std::string(buf + first, 64u - first); + #else + static constexpr char hex[] = "0123456789abcdef"; + + int top = MP_N64 - 1; + while (top > 0 && a[top] == 0) { + --top; + } + + uint64_t x = a[top]; + + int shift = 60; + while (shift > 0 && ((x >> shift) & 0xFu) == 0) { + shift -= 4; + } + + std::string out; + out.reserve((size_t)top * 16u + (size_t)(shift / 4 + 1)); + + for (; shift >= 0; shift -= 4) { + out.push_back(hex[(x >> shift) & 0xFu]); + } + + for (int i = top - 1; i >= 0; --i) { + x = a[i]; + + out.push_back(hex[(x >> 60) & 0xFu]); + out.push_back(hex[(x >> 56) & 0xFu]); + out.push_back(hex[(x >> 52) & 0xFu]); + out.push_back(hex[(x >> 48) & 0xFu]); + out.push_back(hex[(x >> 44) & 0xFu]); + out.push_back(hex[(x >> 40) & 0xFu]); + out.push_back(hex[(x >> 36) & 0xFu]); + out.push_back(hex[(x >> 32) & 0xFu]); + out.push_back(hex[(x >> 28) & 0xFu]); + out.push_back(hex[(x >> 24) & 0xFu]); + out.push_back(hex[(x >> 20) & 0xFu]); + out.push_back(hex[(x >> 16) & 0xFu]); + out.push_back(hex[(x >> 12) & 0xFu]); + out.push_back(hex[(x >> 8) & 0xFu]); + out.push_back(hex[(x >> 4) & 0xFu]); + out.push_back(hex[x & 0xFu]); + } + return out; +#endif + } + + uint64_t v[MP_N64]; + mp_copy(v, a); + + if (base == 10u) { +#if defined(__SIZEOF_INT128__) && MP_N64 == 4 + static constexpr uint64_t DEC_BASE = 10000000000000000000ULL; // 1e19 + + uint64_t q0[MP_N64]; + uint64_t q1[MP_N64]; + uint64_t q2[MP_N64]; + uint64_t q3[MP_N64]; + uint64_t q4[MP_N64]; + + uint64_t chunks[5]; + size_t n_chunks = 0; + + chunks[n_chunks++] = mp_div_u64_base(q0, v, DEC_BASE); + + if (!mp_is_zero(q0)) { + chunks[n_chunks++] = mp_div_u64_base(q1, q0, DEC_BASE); + + if (!mp_is_zero(q1)) { + chunks[n_chunks++] = mp_div_u64_base(q2, q1, DEC_BASE); + + if (!mp_is_zero(q2)) { + chunks[n_chunks++] = mp_div_u64_base(q3, q2, DEC_BASE); + + if (!mp_is_zero(q3)) { + chunks[n_chunks++] = mp_div_u64_base(q4, q3, DEC_BASE); + } + } + } + } + + char buf[(size_t)MP_N64 * 20u + 1u]; + char *end = buf + sizeof(buf); + char *p = end; + + for (size_t i = 0; i + 1 < n_chunks; ++i) { + p = mp_write_dec_19_back(p, chunks[i]); + } + + p = mp_write_dec_u64_back(p, chunks[n_chunks - 1]); + + return std::string(p, (size_t)(end - p)); +#elif defined(__SIZEOF_INT128__) + static constexpr uint64_t DEC_BASE = 10000000000000000000ULL; // 1e19 + + uint64_t chunks[(size_t)MP_N64 * 4u]; + size_t n_chunks = 0; + + while (!mp_is_zero(v)) { + uint64_t q[MP_N64]; + const uint64_t rem = mp_div_u64_base(q, v, DEC_BASE); + + chunks[n_chunks++] = rem; + mp_copy(v, q); + } + + char buf[(size_t)MP_N64 * 20u + 1u]; + char *end = buf + sizeof(buf); + char *p = end; + + for (size_t i = 0; i + 1 < n_chunks; ++i) { + p = mp_write_dec_19_back(p, chunks[i]); + } + + p = mp_write_dec_u64_back(p, chunks[n_chunks - 1]); + + return std::string(p, (size_t)(end - p)); +#else + static constexpr uint32_t DEC_BASE = 1000000000u; // 1e9 + + uint32_t chunks[(size_t)MP_N64 * 8u]; + size_t n_chunks = 0; + + while (!mp_is_zero(v)) { + uint64_t q[MP_N64]; + const uint32_t rem = mp_div(q, v, DEC_BASE); + + chunks[n_chunks++] = rem; + mp_copy(v, q); + } + + char buf[(size_t)MP_N64 * 20u + 1u]; + char *end = buf + sizeof(buf); + char *p = end; + + for (size_t i = 0; i + 1 < n_chunks; ++i) { + p = mp_write_dec_9_back(p, chunks[i]); + } + + p = mp_write_dec_u64_back(p, chunks[n_chunks - 1]); + + return std::string(p, (size_t)(end - p)); +#endif +} + + std::string out; + + while (!mp_is_zero(v)) { + uint64_t q[MP_N64]; + uint32_t rem = mp_div(q, v, base); + + char digit = (rem < 10u) + ? (char)('0' + rem) + : (char)('a' + (rem - 10u)); + + out.push_back(digit); + mp_copy(v, q); + } + + std::reverse(out.begin(), out.end()); + return out; +} + +bool mp_fits_int32(const uint64_t *a) { + for (int i = 1; i < MP_N64; ++i) { + if (a[i] != 0) return false; + } + return a[0] <= (uint64_t)INT32_MAX; +} + +int32_t mp_get_int32(const mp_uint_t a) { + return (int32_t)a[0]; +} + +static inline void mp_add_mod(uint64_t *r, const uint64_t *a, const uint64_t *b, const uint64_t *mod) { + uint64_t carry = mp_add(r, a, b); + + if (carry || mp_cmp(r, mod) >= 0) { + mp_sub(r, r, mod); + } +} + +static inline void mp_mul_mod(uint64_t *r, const uint64_t *a, uint32_t b, const uint64_t *mod) { + uint64_t res[MP_N64]; mp_zero(res); + + uint64_t cur[MP_N64]; + if (mp_cmp(a, mod) >= 0) { + mp_uint_t q, rem; + mp_div(q, rem, a, mod); + mp_copy(cur, rem); + } else { + mp_copy(cur, a); + } + + uint32_t k = b; + while (k) { + if (k & 1u) { + uint64_t tmp[MP_N64]; + mp_add_mod(tmp, res, cur, mod); + mp_copy(res, tmp); + } + k >>= 1u; + if (k) { + uint64_t tmp[MP_N64]; + mp_add_mod(tmp, cur, cur, mod); + mp_copy(cur, tmp); + } + } + mp_copy(r, res); +} + +bool mp_set_mod(uint64_t *r, const char *str, uint32_t base, const uint64_t *mod) { + mp_zero(r); + + if (base == 0u) base = 10u; + if (base < 2u || base > 16u) return false; + + if (base == 16u) { + uint64_t tmp[MP_N64]; + bool neg = false; + + MpHexParseStatus st = mp_parse_hex_u256(tmp, str, true, &neg); + + if (st == MpHexParseStatus::Invalid) { + return false; + } + + if (st == MpHexParseStatus::Ok) { + if (mp_cmp(tmp, mod) >= 0) { + uint64_t q[MP_N64]; + uint64_t rem[MP_N64]; + + mp_div(q, rem, tmp, mod); + mp_copy(tmp, rem); + } + + if (neg && !mp_is_zero(tmp)) { + uint64_t reduced_neg[MP_N64]; + + mp_sub(reduced_neg, mod, tmp); + mp_copy(tmp, reduced_neg); + } + + mp_copy(r, tmp); + return true; + } + } + + while (*str && std::isspace((unsigned char)*str)) str++; + + bool neg = false; + if (*str == '+') str++; + else if (*str == '-') { neg = true; str++; } + + uint64_t acc[MP_N64]; + mp_zero(acc); + + bool any = false; + + auto reduce_small = [&](uint64_t *x) { + // x < mod*base + 15 => at most base subtractions (base <= 16) + while (mp_cmp(x, mod) >= 0) { + mp_sub(x, x, mod); + } + }; + + for (; *str; str++) { + if (std::isspace((unsigned char)*str)) break; + + const char uc = *str; + uint32_t d; + if (uc >= '0' && uc <= '9') { + d = uc - '0'; + } else if (uc >= 'a' && uc <= 'f') { + d = (uc - 'a') + 10u; + } else if (uc >= 'A' && uc <= 'F') { + d = (uc - 'A') + 10u; + } else { + return false; + } + if (d >= base) return false; + +#if !defined(__SIZEOF_INT128__) + { + uint64_t t1[MP_N64]; + mp_mul_mod(t1, acc, base, mod); + uint64_t dv[MP_N64]; + mp_set(dv, d); + uint64_t t2[MP_N64]; + mp_add_mod(t2, t1, dv, mod); + mp_copy(acc, t2); + any = true; + continue; + } +#else + + uint64_t tmp[MP_N64]; + { + __uint128_t carry = 0; + for (size_t i = 0; i < MP_N64; i++) { + __uint128_t prod = (__uint128_t)acc[i] * (__uint128_t)base + carry; + tmp[i] = (uint64_t)prod; + carry = prod >> 2*MP_N; + } + + if (carry) { + uint64_t t1[MP_N64]; + mp_mul_mod(t1, acc, base, mod); + uint64_t dv[MP_N64]; + mp_set(dv, d); + uint64_t t2[MP_N64]; + mp_add_mod(t2, t1, dv, mod); + mp_copy(acc, t2); + any = true; + continue; + } + } + + // tmp += d + { + uint64_t c = d; + + for (size_t i = 0; i < MP_N64 && c; i++) { + uint64_t before = tmp[i]; + tmp[i] += c; + c = tmp[i] < before ? 1u : 0u; + } + + if (c) { + uint64_t t1[MP_N64]; + mp_mul_mod(t1, acc, base, mod); + uint64_t dv[MP_N64]; + mp_set(dv, d); + uint64_t t2[MP_N64]; + mp_add_mod(t2, t1, dv, mod); + mp_copy(acc, t2); + any = true; + continue; + } + } + + mp_copy(acc, tmp); + reduce_small(acc); + any = true; +#endif + } + + if (!any) return false; + + while (*str && std::isspace((unsigned char)*str)) str++; + if (*str != '\0') return false; + + if (neg && !mp_is_zero(acc)) { + uint64_t tmp[MP_N64]; + mp_sub(tmp, mod, acc); + mp_copy(acc, tmp); + } + + mp_copy(r, acc); + return true; +} + +static inline unsigned mp_clz64(uint64_t x) { return x ? __builtin_clzll(x) : 64; } + +static inline void mp_mul64(uint64_t a, uint64_t b, uint64_t &lo, uint64_t &hi) { + const uint64_t a0 = (uint32_t)a; + const uint64_t a1 = a >> MP_N; + const uint64_t b0 = (uint32_t)b; + const uint64_t b1 = b >> MP_N; + + const uint64_t p00 = a0 * b0; + const uint64_t p01 = a0 * b1; + const uint64_t p10 = a1 * b0; + const uint64_t p11 = a1 * b1; + + const uint64_t mid = (p00 >> MP_N) + (uint32_t)p01 + (uint32_t)p10; + lo = (p00 & 0xFFFFFFFFULL) | (mid << MP_N); + hi = p11 + (p01 >> MP_N) + (p10 >> MP_N) + (mid >> MP_N); +} + +static inline int mp_num_limbs(const uint64_t *a) { + for (int i = MP_N64 - 1; i >= 0; --i) { + if (a[i] != 0) return i + 1; + } + + return 0; +} + +static inline uint64_t div_2by1(uint64_t *q, uint64_t hi, uint64_t lo, uint64_t v) { + uint64_t qq = 0; + uint64_t rem = hi; + + for (int bit = (2 * MP_N) - 1; bit >= 0; --bit) { + // Shift remainder left by 1 and bring next bit from lo. + uint64_t overflow = rem >> ((2 * MP_N) - 1); + rem = (rem << 1) | ((lo >> bit) & 1ULL); + + // If previous top bit was 1, actual shifted remainder was >= 2^64. + // Since rem_before < v, shifted remainder < 2*v + 1, so one subtraction is enough. + if (overflow || rem >= v) { + rem -= v; + qq |= (1ULL << bit); + } + } + + *q = qq; + return rem; +} + +static inline uint64_t div_1word(uint64_t *q, const uint64_t *u, uint64_t v) +{ +#if defined(__SIZEOF_INT128__) + __uint128_t rem = 0; + + for (int i = MP_N64 - 1; i >= 0; i--) { + __uint128_t cur = rem << 2*MP_N | (__uint128_t)u[i]; + q[i] = (uint64_t)(cur / v); + rem = (uint64_t)(cur % v); + } + + return (uint64_t)rem; +#else +uint64_t rem = 0; + +for (int i = MP_N64 - 1; i >= 0; --i) { + uint64_t qi; + rem = div_2by1(&qi, rem, u[i], v); + q[i] = qi; +} + +return rem; +#endif +} + +static inline uint64_t mul_sub_knuth(uint64_t *u, const uint64_t *v, int n, uint64_t qhat) +{ +#if defined(__SIZEOF_INT128__) + __uint128_t carry = 0; + uint64_t borrow = 0; + + for (int i = 0; i < n; i++) { + __uint128_t prod = (__uint128_t)qhat * (__uint128_t)v[i] + carry; + uint64_t pl = (uint64_t)prod; + carry = prod >> 2*MP_N; + __int128_t t = (__int128_t)u[i] - (__int128_t)pl - (__int128_t)borrow; + u[i] = (uint64_t)t; + borrow = t < 0 ? 1u : 0u; + } + + __int128_t ttop = (__int128_t)u[n] - (__int128_t)carry - (__int128_t)borrow; + u[n] = (uint64_t)ttop; + + return ttop < 0 ? 1u : 0u; +#else + uint64_t carry = 0; + uint64_t borrow = 0; + + for (int i = 0; i < n; ++i) { + uint64_t hi, lo; + mp_mul64(qhat, v[i], lo, hi); + + // Add previous carry into low part of the product. + uint64_t c = add_carry(&lo, lo, carry, 0); + hi += c; + + // Subtract low limb and incoming borrow from u[i]. + borrow = sub_borrow(&u[i], u[i], lo, borrow); + + // High limb becomes carry for next step. + carry = hi; + } + + // Subtract final carry and borrow from top limb u[n]. + return sub_borrow(&u[n], u[n], carry, borrow); +#endif +} + +static inline uint64_t add_back_knuth(uint64_t *u, const uint64_t *v, int n) +{ +#if defined(__SIZEOF_INT128__) + __uint128_t carry = 0; + + for (int i = 0; i < n; i++) { + __uint128_t t = (__uint128_t)u[i] + (__uint128_t)v[i] + carry; + u[i] = (uint64_t)t; + carry = t >> 2*MP_N; + } + + __uint128_t ttop = (__uint128_t)u[n] + carry; + u[n] = (uint64_t)ttop; + + return (uint64_t)(ttop >> 2*MP_N); +#else + uint64_t carry = 0; + + for (int i = 0; i < n; ++i) { + carry = add_carry(&u[i], u[i], v[i], carry); + } + + return add_carry(&u[n], u[n], 0, carry); +#endif +} + +void mp_div(uint64_t *q, uint64_t *r, const uint64_t *num, const uint64_t *den) { + if (mp_is_zero(den)) { + mp_zero(q); + mp_zero(r); + return; + } + + if (mp_cmp(num, den) < 0) { + mp_zero(q); + mp_copy(r, num); + return; + } + +#if !defined(__SIZEOF_INT128__) + int m = mp_num_limbs(num); + int n = mp_num_limbs(den); + + if (n == 1) { + uint64_t v = den[0]; + mp_uint_t u; + mp_uint_t qq = {0}; + + mp_copy(u, num); + + uint64_t rem = div_1word(qq, u, v); + + mp_copy(q, qq); + mp_set(r, rem); + return; + } + + mp_uint_t vnorm = {0}; + uint64_t unorm[MP_N64 + 1] = {0}; + mp_uint_t vraw; + uint64_t uraw[MP_N64 + 1] = {0}; + + mp_copy(vraw, den); + for (int i = 0; i < MP_N64; ++i) { + uraw[i] = num[i]; + } + uraw[MP_N64] = 0; + + unsigned s = mp_clz64(vraw[n - 1]); + + if (s == 0) { + for (int i = 0; i < n; ++i) vnorm[i] = vraw[i]; + for (int i = n; i < MP_N64; ++i) vnorm[i] = 0; + for (int i = 0; i < MP_N64 + 1; ++i) unorm[i] = uraw[i]; + } else { + uint64_t carry = 0; + for (int i = 0; i < n; ++i) { + uint64_t x = vraw[i]; + vnorm[i] = (x << s) | carry; + carry = x >> ((2 * MP_N) - s); + } + + for (int i = n; i < MP_N64; ++i) vnorm[i] = 0; + + carry = 0; + for (int i = 0; i < MP_N64 + 1; ++i) { + uint64_t x = uraw[i]; + unorm[i] = (x << s) | carry; + carry = x >> ((2 * MP_N) - s); + } + } + + int qn = m - n + 1; + mp_uint_t qlimb = {0}; + + const uint64_t v1 = vnorm[n - 1]; + const uint64_t v2 = vnorm[n - 2]; + + for (int j = qn - 1; j >= 0; --j) { + uint64_t qhat, rhat; + rhat = div_2by1(&qhat, unorm[j + n], unorm[j + n - 1], v1); + + for (;;) { + uint64_t lo, hi; + mp_mul64(qhat, v2, lo, hi); + + bool too_big = false; + if (hi > rhat) { + too_big = true; + } else if (hi == rhat && lo > unorm[j + n - 2]) { + too_big = true; + } + + if (!too_big) break; + + --qhat; + uint64_t old_rhat = rhat; + rhat += v1; + if (rhat < old_rhat) break; + } + + uint64_t *u_seg = &unorm[j]; + uint64_t borrow_out = mul_sub_knuth(u_seg, vnorm, n, qhat); + + if (borrow_out) { + add_back_knuth(u_seg, vnorm, n); + --qhat; + } + + qlimb[j] = qhat; + } + + mp_uint_t rlimb = {0}; + + if (s == 0) { + for (int i = 0; i < n; ++i) rlimb[i] = unorm[i]; + } else { + uint64_t carry = 0; + for (int i = n - 1; i >= 0; --i) { + uint64_t x = unorm[i]; + rlimb[i] = (x >> s) | carry; + carry = x << ((2 * MP_N) - s); + } + } + + mp_copy(q, qlimb); + mp_copy(r, rlimb); + return; +#else + int m = mp_num_limbs(num); + int n = mp_num_limbs(den); + + if (n == 1) { + uint64_t v = den[0]; + mp_uint_t u; + mp_uint_t qq = {}; + + mp_copy(u, num); + + uint64_t rem = div_1word(qq, u, v); + + mp_copy(q, qq); + mp_set(r, rem); + return; + } + + mp_uint_t vnorm = {}; + uint64_t unorm[MP_N64 + 1] = {}; + mp_uint_t vraw; + uint64_t uraw[MP_N64 + 1] = {}; + + mp_copy(vraw, den); + for (int i = 0; i < MP_N64; ++i) { + uraw[i] = num[i]; + } + uraw[MP_N64] = 0; + + unsigned s = mp_clz64(vraw[n - 1]); + + if (s == 0) { + for (int i = 0; i < n; i++) vnorm[i] = vraw[i]; + for (int i = n; i < MP_N64; i++) vnorm[i] = 0; + for (int i = 0; i < MP_N64 + 1; i++) unorm[i] = uraw[i]; + } else { + uint64_t carry = 0; + for (int i = 0; i < n; i++) { + uint64_t x = vraw[i]; + vnorm[i] = x << s | carry; + carry = x >> (2*MP_N - s); + } + + for (int i = n; i < MP_N64; i++) vnorm[i] = 0; + + carry = 0; + + for (int i = 0; i < MP_N64 + 1; i++) { + uint64_t x = uraw[i]; + unorm[i] = x << s | carry; + carry = x >> (2*MP_N - s); + } + } + + int qn = m - n + 1; + mp_uint_t qlimb = {}; + + const uint64_t v1 = vnorm[n - 1]; + const uint64_t v2 = vnorm[n - 2]; + + for (int j = qn - 1; j >= 0; j--) { + uint64_t qhat; + __uint128_t rhat; + + if (unorm[j + n] == v1) { + qhat = UINT64_MAX; + rhat = (__uint128_t)unorm[j + n - 1] + (__uint128_t)v1; + } else { + __uint128_t uj2 = + (__uint128_t)unorm[j + n] << (2*MP_N) | + (__uint128_t)unorm[j + n - 1]; + + qhat = (uint64_t)(uj2 / v1); + rhat = uj2 % v1; + } + + for (;;) { + __uint128_t left = (__uint128_t)qhat * (__uint128_t)v2; + __uint128_t right = (rhat << 2*MP_N) | (__uint128_t)unorm[j + n - 2]; + if (left <= right) break; + + --qhat; + rhat += (__uint128_t)v1; + if (rhat >= (((__uint128_t)1) << 2*MP_N)) break; + } + + uint64_t *u_seg = &unorm[j]; + uint64_t borrow_out = mul_sub_knuth(u_seg, vnorm, n, qhat); + + if (borrow_out) { + add_back_knuth(u_seg, vnorm, n); + qhat--; + } + + qlimb[j] = qhat; + } + + mp_uint_t rlimb = {}; + + if (s == 0) { + for (int i = 0; i < n; i++) rlimb[i] = unorm[i]; + } else { + uint64_t carry = 0; + + for (int i = n - 1; i >= 0; i--) { + uint64_t x = unorm[i]; + rlimb[i] = x >> s | carry; + carry = x << (2*MP_N - s); + } + } + + mp_copy(q, qlimb); + mp_copy(r, rlimb); +#endif +} + +static inline void mp_mul_full(uint64_t *out2n, const uint64_t *a, const uint64_t *b) +{ +#if defined(__SIZEOF_INT128__) + for (int i = 0; i < 2 * MP_N64; ++i) { + out2n[i] = 0; + } + + for (int i = 0; i < MP_N64; ++i) { + __uint128_t carry = 0; + for (int j = 0; j < MP_N64; ++j) { + __uint128_t cur = (__uint128_t)a[i] * (__uint128_t)b[j] + + (__uint128_t)out2n[i + j] + + carry; + out2n[i + j] = (uint64_t)cur; + carry = cur >> (2 * MP_N); + } + + int k = i + MP_N64; + while (carry) { + __uint128_t cur = (__uint128_t)out2n[k] + carry; + out2n[k] = (uint64_t)cur; + carry = cur >> (2 * MP_N); + ++k; + } + } +#else + for (int i = 0; i < 2 * MP_N64; ++i) out2n[i] = 0; + + for (int i = 0; i < MP_N64; ++i) { + uint64_t carry = 0; + + for (int j = 0; j < MP_N64; ++j) { + uint64_t lo, hi; + mp_mul64(a[i], b[j], lo, hi); + + uint64_t x; + uint64_t c0 = add_carry(&x, out2n[i + j], lo, 0); + uint64_t c1 = add_carry(&x, x, carry, 0); + out2n[i + j] = x; + + carry = hi + c0 + c1; + } + + int k = i + MP_N64; + while (carry && k < 2 * MP_N64) { + uint64_t x; + uint64_t c = add_carry(&x, out2n[k], carry, 0); + out2n[k] = x; + carry = c; + ++k; + } + } +#endif +} + +static inline void mp_mod_2n_n(uint64_t *r, const uint64_t *num2n, const uint64_t *den) +{ + const int n = mp_num_limbs(den); + + if (n == 0) { + mp_zero(r); + return; + } + + if (n == 1) { + uint64_t rem = 0; +#if defined(__SIZEOF_INT128__) + for (int i = 2 * MP_N64 - 1; i >= 0; --i) { + __uint128_t cur = ((__uint128_t)rem << (2 * MP_N)) | (__uint128_t)num2n[i]; + rem = (uint64_t)(cur % den[0]); + } +#else + for (int i = 2 * MP_N64 - 1; i >= 0; --i) { + uint64_t qdummy; + rem = div_2by1(&qdummy, rem, num2n[i], den[0]); + } +#endif + mp_set(r, rem); + return; + } + + uint64_t vnorm[MP_N64] = {0}; + uint64_t unorm[2 * MP_N64 + 1] = {0}; + + const unsigned s = mp_clz64(den[n - 1]); + + if (s == 0) { + for (int i = 0; i < n; ++i) { + vnorm[i] = den[i]; + } + for (int i = 0; i < 2 * MP_N64; ++i) { + unorm[i] = num2n[i]; + } + unorm[2 * MP_N64] = 0; + } else { + uint64_t carry = 0; + for (int i = 0; i < n; ++i) { + uint64_t x = den[i]; + vnorm[i] = (x << s) | carry; + carry = x >> ((2 * MP_N) - s); + } + + carry = 0; + for (int i = 0; i < 2 * MP_N64; ++i) { + uint64_t x = num2n[i]; + unorm[i] = (x << s) | carry; + carry = x >> ((2 * MP_N) - s); + } + unorm[2 * MP_N64] = carry; + } + + const uint64_t v1 = vnorm[n - 1]; + const uint64_t v2 = vnorm[n - 2]; + + const int qn = 2 * MP_N64 - n + 1; + + for (int j = qn - 1; j >= 0; --j) { + uint64_t qhat, rhat; + +#if defined(__SIZEOF_INT128__) + __uint128_t uj2 = + ((__uint128_t)unorm[j + n] << (2 * MP_N)) | + (__uint128_t)unorm[j + n - 1]; + + qhat = (uint64_t)(uj2 / v1); + rhat = (uint64_t)(uj2 % v1); + + for (;;) { + __uint128_t left = + (__uint128_t)qhat * (__uint128_t)v2; + __uint128_t right = + ((__uint128_t)rhat << (2 * MP_N)) | + (__uint128_t)unorm[j + n - 2]; + + if (left <= right) break; + + --qhat; + uint64_t old_rhat = rhat; + rhat += v1; + if (rhat < old_rhat) break; + } +#else + rhat = div_2by1(&qhat, unorm[j + n], unorm[j + n - 1], v1); + + for (;;) { + uint64_t lo, hi; + mp_mul64(qhat, v2, lo, hi); + + bool too_big = false; + if (hi > rhat) { + too_big = true; + } else if (hi == rhat && lo > unorm[j + n - 2]) { + too_big = true; + } + + if (!too_big) break; + + --qhat; + uint64_t old_rhat = rhat; + rhat += v1; + if (rhat < old_rhat) break; + } +#endif + + uint64_t borrow_out = mul_sub_knuth(&unorm[j], vnorm, n, qhat); + if (borrow_out) { + add_back_knuth(&unorm[j], vnorm, n); + } + } + + mp_zero(r); + + if (s == 0) { + for (int i = 0; i < n; ++i) { + r[i] = unorm[i]; + } + } else { + uint64_t carry = 0; + for (int i = n - 1; i >= 0; --i) { + uint64_t x = unorm[i]; + r[i] = (x >> s) | carry; + carry = x << ((2 * MP_N) - s); + } + } + + while (mp_cmp(r, den) >= 0) { + mp_sub(r, r, den); + } +} + + +static inline void mp_mulmod(uint64_t *r, const uint64_t *a, const uint64_t *b, const uint64_t *mod) +{ + if (mp_is_zero(mod)) { + mp_zero(r); + return; + } + + uint64_t prod[2 * MP_N64]; + mp_mul_full(prod, a, b); + mp_mod_2n_n(r, prod, mod); +} + +#if MP_N64 == 4 && defined(__SIZEOF_INT128__) + +static inline uint64_t mp_mont_n0inv_4(uint64_t n0) { + // Computes -n0^{-1} mod 2^64. + // Valid only when n0 is odd. + uint64_t x = 1; + + x *= 2ULL - n0 * x; + x *= 2ULL - n0 * x; + x *= 2ULL - n0 * x; + x *= 2ULL - n0 * x; + x *= 2ULL - n0 * x; + x *= 2ULL - n0 * x; + + return (uint64_t)0 - x; +} + +static inline void mp_mont_reduce_4( + uint64_t *r, + const uint64_t *in, + const uint64_t *mod, + uint64_t n0inv +) { + uint64_t t[9] = { + in[0], in[1], in[2], in[3], + in[4], in[5], in[6], in[7], + 0 + }; + + for (int i = 0; i < 4; ++i) { + const uint64_t m = t[i] * n0inv; + + __uint128_t z; + __uint128_t carry = 0; + + z = (__uint128_t)m * mod[0] + t[i + 0] + carry; + t[i + 0] = (uint64_t)z; + carry = z >> 64; + + z = (__uint128_t)m * mod[1] + t[i + 1] + carry; + t[i + 1] = (uint64_t)z; + carry = z >> 64; + + z = (__uint128_t)m * mod[2] + t[i + 2] + carry; + t[i + 2] = (uint64_t)z; + carry = z >> 64; + + z = (__uint128_t)m * mod[3] + t[i + 3] + carry; + t[i + 3] = (uint64_t)z; + carry = z >> 64; + + z = (__uint128_t)t[i + 4] + carry; + t[i + 4] = (uint64_t)z; + + uint64_t c = (uint64_t)(z >> 64); + + for (int k = i + 5; c && k < 9; ++k) { + z = (__uint128_t)t[k] + c; + t[k] = (uint64_t)z; + c = (uint64_t)(z >> 64); + } + } + + r[0] = t[4]; + r[1] = t[5]; + r[2] = t[6]; + r[3] = t[7]; + + if (t[8] != 0 || mp_cmp(r, mod) >= 0) { + mp_sub(r, r, mod); + } +} + +static inline void mp_mont_mul_4( + uint64_t *r, + const uint64_t *a, + const uint64_t *b, + const uint64_t *mod, + uint64_t n0inv +) { + uint64_t prod[8]; + + mp_mul_full(prod, a, b); + mp_mont_reduce_4(r, prod, mod, n0inv); +} + +static inline void mp_mont_compute_r_r2_4( + uint64_t *r_mod, + uint64_t *r2_mod, + const uint64_t *mod +) { + // R = 2^256. + // r_mod = R mod mod. + uint64_t r_full[8] = { + 0, 0, 0, 0, + 1, 0, 0, 0 + }; + + mp_mod_2n_n(r_mod, r_full, mod); + + // r2_mod = R^2 mod mod = (R mod mod)^2 mod mod. + uint64_t prod[8]; + mp_mul_full(prod, r_mod, r_mod); + mp_mod_2n_n(r2_mod, prod, mod); +} + +static inline void mp_to_mont_4( + uint64_t *r, + const uint64_t *a, + const uint64_t *r2_mod, + const uint64_t *mod, + uint64_t n0inv +) { + // aM = a * R mod mod = REDC(a * R^2) + mp_mont_mul_4(r, a, r2_mod, mod, n0inv); +} + +static inline void mp_from_mont_4( + uint64_t *r, + const uint64_t *a_mont, + const uint64_t *mod, + uint64_t n0inv +) { + uint64_t one[4] = {1, 0, 0, 0}; + + // a = REDC(aM * 1) + mp_mont_mul_4(r, a_mont, one, mod, n0inv); +} + +struct MpMontCtx4 { + uint64_t mod[4]; + uint64_t r_mod[4]; + uint64_t r2_mod[4]; + uint64_t n0inv; +}; + +static constexpr MpMontCtx4 MP_MONT_BN254_FQ = { + { + 0x3c208c16d87cfd47ULL, + 0x97816a916871ca8dULL, + 0xb85045b68181585dULL, + 0x30644e72e131a029ULL + }, + { + 0xd35d438dc58f0d9dULL, + 0x0a78eb28f5c70b3dULL, + 0x666ea36f7879462cULL, + 0x0e0a77c19a07df2fULL + }, + { + 0xf32cfc5b538afa89ULL, + 0xb5e71911d44501fbULL, + 0x47ab1eff0a417ff6ULL, + 0x06d89f71cab8351fULL + }, + 0x87d20782e4866389ULL +}; + +static constexpr MpMontCtx4 MP_MONT_BN254_FR = { + { + 0x43e1f593f0000001ULL, + 0x2833e84879b97091ULL, + 0xb85045b68181585dULL, + 0x30644e72e131a029ULL + }, + { + 0xac96341c4ffffffbULL, + 0x36fc76959f60cd29ULL, + 0x666ea36f7879462eULL, + 0x0e0a77c19a07df2fULL + }, + { + 0x1bb8e645ae216da7ULL, + 0x53fe3ab1e35c59e3ULL, + 0x8c49833d53bb8085ULL, + 0x0216d0b17f4e44a5ULL + }, + 0xc2e1f593efffffffULL +}; + +static inline bool mp_mont_mod_eq_4(const uint64_t *a, const uint64_t *b) { + return ((a[0] ^ b[0]) | + (a[1] ^ b[1]) | + (a[2] ^ b[2]) | + (a[3] ^ b[3])) == 0; +} + +static inline const MpMontCtx4 *mp_mont_get_known_ctx_4(const uint64_t *mod) { + if (mp_mont_mod_eq_4(mod, MP_MONT_BN254_FQ.mod)) { + return &MP_MONT_BN254_FQ; + } + + if (mp_mont_mod_eq_4(mod, MP_MONT_BN254_FR.mod)) { + return &MP_MONT_BN254_FR; + } + + return nullptr; +} + + +static inline int mp_exp_popcount_4(const uint64_t *exp) { + return __builtin_popcountll(exp[0]) + + __builtin_popcountll(exp[1]) + + __builtin_popcountll(exp[2]) + + __builtin_popcountll(exp[3]); +} + +static inline void mp_pow_mod_mont_windowed_4( + uint64_t *r, + const uint64_t *base, + const uint64_t *exp, + const uint64_t *mod, + uint64_t n0inv, + const uint64_t *r2_mod, + int topBit, + int windowBits +) { + // Supports windowBits 4 or 5. Table stores odd powers: 1,3,...,(2^w - 1). + uint64_t table[16][4]; + const int tableSize = 1 << (windowBits - 1); + + // table[0] = base^1 in Montgomery form. + mp_to_mont_4(table[0], base, r2_mod, mod, n0inv); + + // b2 = base^2 in Montgomery form. + uint64_t b2[4]; + mp_mont_mul_4(b2, table[0], table[0], mod, n0inv); + + // table[i] = base^(2*i + 1) in Montgomery form. + for (int i = 1; i < tableSize; ++i) { + mp_mont_mul_4(table[i], table[i - 1], b2, mod, n0inv); + } + + uint64_t one[4]; + mp_set(one, 1u); + + uint64_t acc[4]; + mp_to_mont_4(acc, one, r2_mod, mod, n0inv); + + for (int i = topBit; i >= 0;) { + const int limb = i / (2 * MP_N); + const int bit = i % (2 * MP_N); + + if (((exp[limb] >> bit) & 1ULL) == 0) { + uint64_t sq[4]; + mp_mont_mul_4(sq, acc, acc, mod, n0inv); + mp_copy(acc, sq); + --i; + continue; + } + + int width = std::min(windowBits, i + 1); + int low = i - width + 1; + + // Keep the selected window odd by moving its low end to a set bit. + while (low < i) { + const int low_limb = low / (2 * MP_N); + const int low_bit = low % (2 * MP_N); + + if ((exp[low_limb] >> low_bit) & 1ULL) { + break; + } + + ++low; + --width; + } + + unsigned window = 0; + for (int j = i; j >= low; --j) { + const int j_limb = j / (2 * MP_N); + const int j_bit = j % (2 * MP_N); + window = (window << 1) | (unsigned)((exp[j_limb] >> j_bit) & 1ULL); + } + + for (int j = 0; j < width; ++j) { + uint64_t sq[4]; + mp_mont_mul_4(sq, acc, acc, mod, n0inv); + mp_copy(acc, sq); + } + + uint64_t tmp[4]; + mp_mont_mul_4(tmp, acc, table[window >> 1], mod, n0inv); + mp_copy(acc, tmp); + + i = low - 1; + } + + mp_from_mont_4(r, acc, mod, n0inv); +} + +#endif + +void mp_pow_mod(uint64_t *r, const uint64_t *base, const uint64_t *exp, const uint64_t *mod) +{ + mp_uint_t one; + mp_set(one, 1u); + + if (mp_cmp(mod, one) == 0) { + mp_zero(r); + return; + } + + mp_uint_t bcur; + + if (mp_cmp(base, mod) >= 0) { + mp_uint_t q, rem; + mp_div(q, rem, base, mod); + mp_copy(bcur, rem); + } else { + mp_copy(bcur, base); + } + + int topBit = -1; + + for (int limb = MP_N64 - 1; limb >= 0 && topBit < 0; --limb) { + uint64_t w = exp[limb]; + + if (!w) { + continue; + } + + for (int bit = 2 * MP_N - 1; bit >= 0; --bit) { + if ((w >> bit) & 1u) { + topBit = limb * 2 * MP_N + bit; + break; + } + } + } + + if (topBit < 0) { + mp_copy(r, one); + return; + } + +#if MP_N64 == 4 && defined(__SIZEOF_INT128__) + if ((mod[0] & 1ULL) != 0) { + uint64_t n0inv; + uint64_t r2_mod_local[4]; + const uint64_t *r2_mod_ptr = nullptr; + + const MpMontCtx4 *ctx = mp_mont_get_known_ctx_4(mod); + + if (ctx) { + n0inv = ctx->n0inv; + r2_mod_ptr = ctx->r2_mod; + } else { + n0inv = mp_mont_n0inv_4(mod[0]); + + uint64_t r_mod_local[4]; + mp_mont_compute_r_r2_4(r_mod_local, r2_mod_local, mod); + + r2_mod_ptr = r2_mod_local; + } + + const int popcnt = mp_exp_popcount_4(exp); + + if (topBit >= 191 && popcnt >= 64) { + mp_pow_mod_mont_windowed_4(r, bcur, exp, mod, n0inv, r2_mod_ptr, topBit, 5); + return; + } + + if (topBit >= 63 && popcnt >= 16) { + mp_pow_mod_mont_windowed_4(r, bcur, exp, mod, n0inv, r2_mod_ptr, topBit, 4); + return; + } + + uint64_t b_mont[4]; + uint64_t acc_mont[4]; + + mp_to_mont_4(b_mont, bcur, r2_mod_ptr, mod, n0inv); + mp_copy(acc_mont, b_mont); + + for (int i = topBit - 1; i >= 0; --i) { + uint64_t sq[4]; + + mp_mont_mul_4(sq, acc_mont, acc_mont, mod, n0inv); + mp_copy(acc_mont, sq); + + const int limb = i / (2 * MP_N); + const int bit = i % (2 * MP_N); + + if ((exp[limb] >> bit) & 1u) { + uint64_t tmp[4]; + + mp_mont_mul_4(tmp, acc_mont, b_mont, mod, n0inv); + mp_copy(acc_mont, tmp); + } + } + + mp_from_mont_4(r, acc_mont, mod, n0inv); + return; + } +#endif + + mp_uint_t acc; + mp_copy(acc, bcur); + + for (int i = topBit - 1; i >= 0; --i) { + mp_uint_t sq; + + mp_mulmod(sq, acc, acc, mod); + mp_copy(acc, sq); + + const int limb = i / (2 * MP_N); + const int bit = i % (2 * MP_N); + + if ((exp[limb] >> bit) & 1u) { + mp_uint_t tmp; + + mp_mulmod(tmp, acc, bcur, mod); + mp_copy(acc, tmp); + } + } + + mp_copy(r, acc); +} + +void mp_set_mod(uint64_t *r, int64_t a, const uint64_t *mod) { + if (a >= 0) { + mp_set(r, (uint64_t)a); + + if (mp_cmp(r, mod) >= 0) { + uint64_t q[MP_N64], rem[MP_N64]; + mp_div(q, rem, r, mod); + mp_copy(r, rem); + } + + return; + } + +#if defined(__SIZEOF_INT128__) + uint64_t absv = (uint64_t)(-((__int128_t)a)); +#else + uint64_t absv = (uint64_t)(-(uint64_t)a); +#endif + + uint64_t av[MP_N64]; + mp_set(av, absv); + + if (mp_is_zero(av)) { + mp_zero(r); + return; + } + + if (mp_cmp(av, mod) >= 0) { + uint64_t q[MP_N64], rem[MP_N64]; + mp_div(q, rem, av, mod); + mp_copy(av, rem); + } + + if (mp_is_zero(av)) { + mp_zero(r); + return; + } + + mp_sub(r, mod, av); +} + +uint64_t mp_mul(uint64_t *r, const uint64_t *a, uint64_t b) { +#if defined(__SIZEOF_INT128__) && MP_N64 == 4 + __uint128_t t; + + t = (__uint128_t)a[0] * b; + r[0] = (uint64_t)t; + t >>= 64; + + t += (__uint128_t)a[1] * b; + r[1] = (uint64_t)t; + t >>= 64; + + t += (__uint128_t)a[2] * b; + r[2] = (uint64_t)t; + t >>= 64; + + t += (__uint128_t)a[3] * b; + r[3] = (uint64_t)t; + + return (uint64_t)(t >> 64); + +#elif defined(__SIZEOF_INT128__) + __uint128_t carry = 0; + for (int i = 0; i < MP_N64; i++) { + __uint128_t t = (__uint128_t)a[i] * (__uint128_t)b + carry; + r[i] = (uint64_t)t; + carry = t >> 64; + } + return (uint64_t)carry; +#else + uint64_t carry = 0; + for (int i = 0; i < MP_N64; i++) { + uint64_t lo, hi; + mp_mul64(a[i], b, lo, hi); + + uint64_t out = lo + carry; + hi += (out < lo); + + r[i] = out; + carry = hi; + } + return carry; +#endif +} + +uint64_t mp_addmul(uint64_t *r, const uint64_t *a, size_t n, uint64_t b) +{ +#if defined(__SIZEOF_INT128__) + +#if MP_N64 == 4 + // mp_addmul(productX, pRawB, Fq_N64/Fr_N64=4, pRawA[i]) + if (n == 4) { + const __uint128_t p0 = (__uint128_t)a[0] * b; + const __uint128_t p1 = (__uint128_t)a[1] * b; + const __uint128_t p2 = (__uint128_t)a[2] * b; + const __uint128_t p3 = (__uint128_t)a[3] * b; + + const uint64_t lo0 = (uint64_t)p0; + const uint64_t lo1 = (uint64_t)p1; + const uint64_t lo2 = (uint64_t)p2; + const uint64_t lo3 = (uint64_t)p3; + + uint64_t x0; + uint64_t x1; + uint64_t x2; + uint64_t x3; + + uint64_t c; + + /* + * First carry-chain: + * + * r0 + lo0 + * r1 + hi0 + * r2 + hi1 + * r3 + hi2 + * hi3 + */ + c = add_carry( + &x0, + r[0], + lo0, + 0 + ); + + c = add_carry( + &x1, + r[1], + (uint64_t)(p0 >> 64), + c + ); + + c = add_carry( + &x2, + r[2], + (uint64_t)(p1 >> 64), + c + ); + + c = add_carry( + &x3, + r[3], + (uint64_t)(p2 >> 64), + c + ); + + uint64_t top = (uint64_t)(p3 >> 64) + c; + + /* + * Second carry-chain: + * + * x1 + lo1 + * x2 + lo2 + * x3 + lo3 + */ + c = add_carry(&x1, x1, lo1, 0); + c = add_carry(&x2, x2, lo2, c); + c = add_carry(&x3, x3, lo3, c); + + top += c; + + r[0] = x0; + r[1] = x1; + r[2] = x2; + r[3] = x3; + + return top; + } + + if (n == 5 && a[4] == 0) { + __uint128_t t; + + t = (__uint128_t)r[0] + (__uint128_t)a[0] * (__uint128_t)b; + r[0] = (uint64_t)t; + t >>= 2*MP_N; + + t += (__uint128_t)r[1] + (__uint128_t)a[1] * (__uint128_t)b; + r[1] = (uint64_t)t; + t >>= 2*MP_N; + + t += (__uint128_t)r[2] + (__uint128_t)a[2] * (__uint128_t)b; + r[2] = (uint64_t)t; + t >>= 2*MP_N; + + t += (__uint128_t)r[3] + (__uint128_t)a[3] * (__uint128_t)b; + r[3] = (uint64_t)t; + t >>= 2*MP_N; + + // a[4] == 0, so only propagate carry into r[4]. + t += (__uint128_t)r[4]; + r[4] = (uint64_t)t; + + return (uint64_t)(t >> 2*MP_N); + } + + // mp_addmul(productX, mq, N=5, np0) + if (n == 5) { + __uint128_t t; + + t = (__uint128_t)r[0] + (__uint128_t)a[0] * (__uint128_t)b; + r[0] = (uint64_t)t; + t >>= 2*MP_N; + + t += (__uint128_t)r[1] + (__uint128_t)a[1] * (__uint128_t)b; + r[1] = (uint64_t)t; + t >>= 2*MP_N; + + t += (__uint128_t)r[2] + (__uint128_t)a[2] * (__uint128_t)b; + r[2] = (uint64_t)t; + t >>= 2*MP_N; + + t += (__uint128_t)r[3] + (__uint128_t)a[3] * (__uint128_t)b; + r[3] = (uint64_t)t; + t >>= 2*MP_N; + + t += (__uint128_t)r[4] + (__uint128_t)a[4] * (__uint128_t)b; + r[4] = (uint64_t)t; + + return (uint64_t)(t >> 2*MP_N); + } + +#endif + + __uint128_t carry = 0; + + for (size_t i = 0; i < n; i++) { + __uint128_t t = (__uint128_t)r[i] + + (__uint128_t)a[i] * (__uint128_t)b + + carry; + r[i] = (uint64_t)t; + carry = t >> 2*MP_N; + } + + return (uint64_t)carry; + +#else + uint64_t carry = 0; + + for (size_t i = 0; i < n; i++) { + uint64_t lo, hi; + mp_mul64(a[i], b, lo, hi); + + uint64_t t = r[i] + lo; + uint64_t c1 = (t < r[i]); + + uint64_t out = t + carry; + uint64_t c2 = (out < t); + + r[i] = out; + carry = hi + c1 + c2; + } + + return carry; +#endif +} + +uint64_t mp_add(uint64_t *r, const uint64_t *a, size_t an, const uint64_t *b, size_t bn) { +#if defined(__SIZEOF_INT128__) + if (an == 5 && bn == 4) { + __uint128_t t; + + t = (__uint128_t)a[0] + b[0]; + r[0] = (uint64_t)t; + t >>= 64; + + t += (__uint128_t)a[1] + b[1]; + r[1] = (uint64_t)t; + t >>= 64; + + t += (__uint128_t)a[2] + b[2]; + r[2] = (uint64_t)t; + t >>= 64; + + t += (__uint128_t)a[3] + b[3]; + r[3] = (uint64_t)t; + t >>= 64; + + t += (__uint128_t)a[4]; + r[4] = (uint64_t)t; + + return (uint64_t)(t >> 64); + } +#endif + + size_t n = (an > bn) ? an : bn; + uint64_t carry = 0; + + for (size_t i = 0; i < n; i++) { + uint64_t ai = (i < an) ? a[i] : 0; + uint64_t bi = (i < bn) ? b[i] : 0; + carry = add_carry(&r[i], ai, bi, carry); + } + + return carry; +} + +static inline int mp_is_even(const uint64_t *a) { + return ((a[0] & 1ULL) == 0ULL); +} + +static inline bool mp_is_one(const uint64_t *a) { + if (a[0] != 1ULL) return false; + for (int i = 1; i < MP_N64; i++) { + if (a[i] != 0ULL) return false; + } + return true; +} + +static inline void mp_sub_mod(uint64_t *x, const uint64_t *y, const uint64_t *mod) { +#if MP_N64 == 4 //fast path + uint64_t t0, t1, t2, t3; + uint64_t br = 0; + + br = sub_borrow(&t0, x[0], y[0], br); + br = sub_borrow(&t1, x[1], y[1], br); + br = sub_borrow(&t2, x[2], y[2], br); + br = sub_borrow(&t3, x[3], y[3], br); + + if (br) { + uint64_t c = 0; + c = add_carry(&t0, t0, mod[0], c); + c = add_carry(&t1, t1, mod[1], c); + c = add_carry(&t2, t2, mod[2], c); + c = add_carry(&t3, t3, mod[3], c); + } + + x[0] = t0; x[1] = t1; x[2] = t2; x[3] = t3; +#else + uint64_t t[MP_N64]; + uint64_t br = 0; + + for (int i = 0; i < MP_N64; i++) { + br = sub_borrow(&t[i], x[i], y[i], br); + } + + if (br) { + uint64_t c = 0; + for (int i = 0; i < MP_N64; i++) { + c = add_carry(&t[i], t[i], mod[i], c); + } + } + + mp_copy(x, t); +#endif +} + +static inline void mp_shr1(uint64_t *x) { +#if MP_N64 == 4 + const uint64_t x0 = x[0]; + const uint64_t x1 = x[1]; + const uint64_t x2 = x[2]; + const uint64_t x3 = x[3]; + + x[0] = (x0 >> 1) | (x1 << 63); + x[1] = (x1 >> 1) | (x2 << 63); + x[2] = (x2 >> 1) | (x3 << 63); + x[3] = (x3 >> 1); +#else + uint64_t hi = 0; + + for (int i = MP_N64 - 1; i >= 0; --i) { + uint64_t new_hi = x[i] & 1ULL; + x[i] = (x[i] >> 1) | (hi << 63); + hi = new_hi; + } +#endif +} + +static inline void mp_div2_mod(uint64_t *x, const uint64_t *mod) { +#if MP_N64 == 4 + uint64_t hi = 0; + + if (x[0] & 1ULL) { + uint64_t c = 0; + + c = add_carry(&x[0], x[0], mod[0], c); + c = add_carry(&x[1], x[1], mod[1], c); + c = add_carry(&x[2], x[2], mod[2], c); + c = add_carry(&x[3], x[3], mod[3], c); + + hi = c; + } + + const uint64_t x0 = x[0]; + const uint64_t x1 = x[1]; + const uint64_t x2 = x[2]; + const uint64_t x3 = x[3]; + + x[0] = (x0 >> 1) | (x1 << 63); + x[1] = (x1 >> 1) | (x2 << 63); + x[2] = (x2 >> 1) | (x3 << 63); + x[3] = (x3 >> 1) | (hi << 63); +#else + uint64_t hi = 0; + + if (x[0] & 1ULL) { + uint64_t c = 0; + for (int i = 0; i < MP_N64; ++i) { + c = add_carry(&x[i], x[i], mod[i], c); + } + hi = c; + } + + for (int i = MP_N64 - 1; i >= 0; --i) { + uint64_t new_hi = x[i] & 1ULL; + x[i] = (x[i] >> 1) | (hi << 63); + hi = new_hi; + } +#endif +} + +static inline bool mp_inv_mod_bin(uint64_t *r, const uint64_t *a, const uint64_t *mod) { + uint64_t u[MP_N64], v[MP_N64]; + mp_copy(u, a); + mp_copy(v, mod); + + if (mp_is_zero(u)) { mp_zero(r); return false; } + + uint64_t x1[MP_N64], x2[MP_N64]; + mp_set(x1, 1u); + mp_zero(x2); + + while (!mp_is_one(u) && !mp_is_one(v)) { + + while (mp_is_even(u)) { + mp_shr1(u); + mp_div2_mod(x1, mod); + } + + while (mp_is_even(v)) { + mp_shr1(v); + mp_div2_mod(x2, mod); + } + + if (mp_cmp(u, v) >= 0) { + mp_sub(u, u, v); + mp_sub_mod(x1, x2, mod); // x1 = x1 - x2 (mod) + } else { + mp_sub(v, v, u); + mp_sub_mod(x2, x1, mod); // x2 = x2 - x1 (mod) + } + } + + if (mp_is_one(u)) mp_copy(r, x1); + else mp_copy(r, x2); + return true; +} + +#if MP_N64 == 4 && defined(__SIZEOF_INT128__) + +struct MpInvSigned62 { + int64_t v[5]; +}; + +struct MpInvTrans2x2 { + int64_t u; + int64_t v; + int64_t q; + int64_t r; +}; + +static constexpr uint64_t MP_INV_M62_U = UINT64_MAX >> 2; +static constexpr int64_t MP_INV_M62_S = (int64_t)(UINT64_MAX >> 2); + +static inline bool mp_inv_is_zero4(const uint64_t *x) { + return (x[0] | x[1] | x[2] | x[3]) == 0; +} + +static inline uint64_t mp_inv_mod2_62(uint64_t a) { + uint64_t x = 1; + + x *= 2ULL - a * x; + x *= 2ULL - a * x; + x *= 2ULL - a * x; + x *= 2ULL - a * x; + x *= 2ULL - a * x; + x *= 2ULL - a * x; + + return x & MP_INV_M62_U; +} + +static inline void mp_inv_to_signed62(MpInvSigned62 *r, const uint64_t *x) { + r->v[0] = (int64_t)(x[0] & MP_INV_M62_U); + r->v[1] = (int64_t)((x[0] >> 62) | ((x[1] & ((1ULL << 60) - 1ULL)) << 2)); + r->v[2] = (int64_t)((x[1] >> 60) | ((x[2] & ((1ULL << 58) - 1ULL)) << 4)); + r->v[3] = (int64_t)((x[2] >> 58) | ((x[3] & ((1ULL << 56) - 1ULL)) << 6)); + r->v[4] = (int64_t)(x[3] >> 56); +} + +static inline void mp_inv_from_signed62(uint64_t *r, const MpInvSigned62 *x) { + const uint64_t x0 = (uint64_t)x->v[0]; + const uint64_t x1 = (uint64_t)x->v[1]; + const uint64_t x2 = (uint64_t)x->v[2]; + const uint64_t x3 = (uint64_t)x->v[3]; + const uint64_t x4 = (uint64_t)x->v[4]; + + r[0] = x0 | (x1 << 62); + r[1] = (x1 >> 2) | (x2 << 60); + r[2] = (x2 >> 4) | (x3 << 58); + r[3] = (x3 >> 6) | (x4 << 56); +} + +static inline int mp_inv_ctz64_var(uint64_t x) { + return __builtin_ctzll(x); +} + +static inline int64_t mp_inv_divsteps_62_var( + int64_t eta, + uint64_t f0, + uint64_t g0, + MpInvTrans2x2 *t +) { + uint64_t u = 1; + uint64_t v = 0; + uint64_t q = 0; + uint64_t r = 1; + uint64_t f = f0; + uint64_t g = g0; + + int i = 62; + + for (;;) { + const int zeros = mp_inv_ctz64_var(g | (UINT64_MAX << i)); + + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + + if (i == 0) { + break; + } + + int limit; + uint64_t mask; + uint32_t w; + + if (eta < 0) { + uint64_t tmp; + + eta = -eta; + + tmp = f; f = g; g = -tmp; + tmp = u; u = q; q = -tmp; + tmp = v; v = r; r = -tmp; + + limit = ((int)eta + 1 > i) ? i : ((int)eta + 1); + mask = (UINT64_MAX >> (64 - limit)) & 63U; + w = (uint32_t)((f * g * (f * f - 2U)) & mask); + } else { + limit = ((int)eta + 1 > i) ? i : ((int)eta + 1); + mask = (UINT64_MAX >> (64 - limit)) & 15U; + w = (uint32_t)(f + (((f + 1U) & 4U) << 1)); + w = (uint32_t)((-(uint64_t)w * g) & mask); + } + + g += f * w; + q += u * w; + r += v * w; + } + + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + return eta; +} + +static inline void mp_inv_update_fg_62_var( + int len, + MpInvSigned62 *f, + MpInvSigned62 *g, + const MpInvTrans2x2 *t +) { + const int64_t u = t->u; + const int64_t v = t->v; + const int64_t q = t->q; + const int64_t r = t->r; + + __int128 cf = (__int128)u * f->v[0] + (__int128)v * g->v[0]; + __int128 cg = (__int128)q * f->v[0] + (__int128)r * g->v[0]; + + cf >>= 62; + cg >>= 62; + + for (int i = 1; i < len; ++i) { + cf += (__int128)u * f->v[i] + (__int128)v * g->v[i]; + cg += (__int128)q * f->v[i] + (__int128)r * g->v[i]; + + f->v[i - 1] = (int64_t)((uint64_t)cf & MP_INV_M62_U); + cf >>= 62; + + g->v[i - 1] = (int64_t)((uint64_t)cg & MP_INV_M62_U); + cg >>= 62; + } + + f->v[len - 1] = (int64_t)cf; + g->v[len - 1] = (int64_t)cg; +} + +static inline void mp_inv_update_de_62( + MpInvSigned62 *d, + MpInvSigned62 *e, + const MpInvTrans2x2 *t, + const MpInvSigned62 *mod, + uint64_t mod_inv62 +) { + const int64_t d0 = d->v[0]; + const int64_t d1 = d->v[1]; + const int64_t d2 = d->v[2]; + const int64_t d3 = d->v[3]; + const int64_t d4 = d->v[4]; + + const int64_t e0 = e->v[0]; + const int64_t e1 = e->v[1]; + const int64_t e2 = e->v[2]; + const int64_t e3 = e->v[3]; + const int64_t e4 = e->v[4]; + + const int64_t u = t->u; + const int64_t v = t->v; + const int64_t q = t->q; + const int64_t r = t->r; + + const int64_t sd = d4 >> 63; + const int64_t se = e4 >> 63; + + int64_t md = (u & sd) + (v & se); + int64_t me = (q & sd) + (r & se); + + __int128 cd = (__int128)u * d0 + (__int128)v * e0; + __int128 ce = (__int128)q * d0 + (__int128)r * e0; + + md -= (int64_t)((mod_inv62 * (uint64_t)cd + (uint64_t)md) & MP_INV_M62_U); + me -= (int64_t)((mod_inv62 * (uint64_t)ce + (uint64_t)me) & MP_INV_M62_U); + + cd += (__int128)mod->v[0] * md; + ce += (__int128)mod->v[0] * me; + cd >>= 62; + ce >>= 62; + + cd += (__int128)u * d1 + (__int128)v * e1 + (__int128)mod->v[1] * md; + ce += (__int128)q * d1 + (__int128)r * e1 + (__int128)mod->v[1] * me; + d->v[0] = (int64_t)((uint64_t)cd & MP_INV_M62_U); + cd >>= 62; + e->v[0] = (int64_t)((uint64_t)ce & MP_INV_M62_U); + ce >>= 62; + + cd += (__int128)u * d2 + (__int128)v * e2 + (__int128)mod->v[2] * md; + ce += (__int128)q * d2 + (__int128)r * e2 + (__int128)mod->v[2] * me; + d->v[1] = (int64_t)((uint64_t)cd & MP_INV_M62_U); + cd >>= 62; + e->v[1] = (int64_t)((uint64_t)ce & MP_INV_M62_U); + ce >>= 62; + + cd += (__int128)u * d3 + (__int128)v * e3 + (__int128)mod->v[3] * md; + ce += (__int128)q * d3 + (__int128)r * e3 + (__int128)mod->v[3] * me; + d->v[2] = (int64_t)((uint64_t)cd & MP_INV_M62_U); + cd >>= 62; + e->v[2] = (int64_t)((uint64_t)ce & MP_INV_M62_U); + ce >>= 62; + + cd += (__int128)u * d4 + (__int128)v * e4 + (__int128)mod->v[4] * md; + ce += (__int128)q * d4 + (__int128)r * e4 + (__int128)mod->v[4] * me; + d->v[3] = (int64_t)((uint64_t)cd & MP_INV_M62_U); + cd >>= 62; + e->v[3] = (int64_t)((uint64_t)ce & MP_INV_M62_U); + ce >>= 62; + + d->v[4] = (int64_t)cd; + e->v[4] = (int64_t)ce; +} + +static inline void mp_inv_normalize_62( + MpInvSigned62 *r, + int64_t sign, + const MpInvSigned62 *mod +) { + int64_t r0 = r->v[0]; + int64_t r1 = r->v[1]; + int64_t r2 = r->v[2]; + int64_t r3 = r->v[3]; + int64_t r4 = r->v[4]; + + int64_t cond_add = r4 >> 63; + + r0 += mod->v[0] & cond_add; + r1 += mod->v[1] & cond_add; + r2 += mod->v[2] & cond_add; + r3 += mod->v[3] & cond_add; + r4 += mod->v[4] & cond_add; + + const int64_t cond_negate = sign >> 63; + + r0 = (r0 ^ cond_negate) - cond_negate; + r1 = (r1 ^ cond_negate) - cond_negate; + r2 = (r2 ^ cond_negate) - cond_negate; + r3 = (r3 ^ cond_negate) - cond_negate; + r4 = (r4 ^ cond_negate) - cond_negate; + + r1 += r0 >> 62; r0 &= MP_INV_M62_S; + r2 += r1 >> 62; r1 &= MP_INV_M62_S; + r3 += r2 >> 62; r2 &= MP_INV_M62_S; + r4 += r3 >> 62; r3 &= MP_INV_M62_S; + + cond_add = r4 >> 63; + + r0 += mod->v[0] & cond_add; + r1 += mod->v[1] & cond_add; + r2 += mod->v[2] & cond_add; + r3 += mod->v[3] & cond_add; + r4 += mod->v[4] & cond_add; + + r1 += r0 >> 62; r0 &= MP_INV_M62_S; + r2 += r1 >> 62; r1 &= MP_INV_M62_S; + r3 += r2 >> 62; r2 &= MP_INV_M62_S; + r4 += r3 >> 62; r3 &= MP_INV_M62_S; + + r->v[0] = r0; + r->v[1] = r1; + r->v[2] = r2; + r->v[3] = r3; + r->v[4] = r4; +} + +static bool mp_inv_mod_safegcd_4(uint64_t *r, const uint64_t *a, const uint64_t *mod) { + if (mp_inv_is_zero4(a)) { + mp_zero(r); + return false; + } + + MpInvSigned62 mod62; + MpInvSigned62 x; + + mp_inv_to_signed62(&mod62, mod); + mp_inv_to_signed62(&x, a); + + const uint64_t mod_inv62 = mp_inv_mod2_62((uint64_t)mod62.v[0]); + + MpInvSigned62 d = {{0, 0, 0, 0, 0}}; + MpInvSigned62 e = {{1, 0, 0, 0, 0}}; + MpInvSigned62 f = mod62; + MpInvSigned62 g = x; + + int len = 5; + int64_t eta = -1; + + for (int guard = 0; guard < 20; ++guard) { + MpInvTrans2x2 t; + + eta = mp_inv_divsteps_62_var(eta, (uint64_t)f.v[0], (uint64_t)g.v[0], &t); + mp_inv_update_de_62(&d, &e, &t, &mod62, mod_inv62); + mp_inv_update_fg_62_var(len, &f, &g, &t); + + if (g.v[0] == 0) { + int64_t cond = 0; + for (int j = 1; j < len; ++j) { + cond |= g.v[j]; + } + if (cond == 0) { + mp_inv_normalize_62(&d, f.v[len - 1], &mod62); + mp_inv_from_signed62(r, &d); + return true; + } + } + + const int64_t fn = f.v[len - 1]; + const int64_t gn = g.v[len - 1]; + int64_t cond = ((int64_t)len - 2) >> 63; + + cond |= fn ^ (fn >> 63); + cond |= gn ^ (gn >> 63); + + if (cond == 0) { + f.v[len - 2] |= (uint64_t)fn << 62; + g.v[len - 2] |= (uint64_t)gn << 62; + --len; + } + } + + mp_zero(r); + return false; +} + +#endif + +bool mp_inv_mod(uint64_t *r, const uint64_t *a, const uint64_t *mod) { +#if MP_N64 == 4 && defined(__SIZEOF_INT128__) + if ((mod[0] & 1ULL) != 0) { + return mp_inv_mod_safegcd_4(r, a, mod); + } +#endif + + return mp_inv_mod_bin(r, a, mod); +} \ No newline at end of file diff --git a/src/mp.hpp.ejs b/src/mp.hpp.ejs new file mode 100644 index 0000000..4f42df9 --- /dev/null +++ b/src/mp.hpp.ejs @@ -0,0 +1,233 @@ +#ifndef MP_HPP +#define MP_HPP + +#include +#include +#include +#include + +#define MP_N64 <%= n64 %> +#define MP_N 32 + +typedef uint64_t mp_uint_t[MP_N64]; + +static inline void mp_zero(uint64_t *r) { +#if MP_N64 == 4 + r[0] = 0; + r[1] = 0; + r[2] = 0; + r[3] = 0; +#else + std::memset(r, 0, MP_N64 * sizeof(uint64_t)); +#endif +} + +static inline void mp_copy(uint64_t *r, const uint64_t *a) { + if (r == a) return; + +#if MP_N64 == 4 + const uintptr_t rp = reinterpret_cast(r); + const uintptr_t ap = reinterpret_cast(a); + static constexpr uintptr_t BYTES = MP_N64 * sizeof(uint64_t); + + if (rp > ap && rp < ap + BYTES) { + r[3] = a[3]; + r[2] = a[2]; + r[1] = a[1]; + r[0] = a[0]; + return; + } + + r[0] = a[0]; + r[1] = a[1]; + r[2] = a[2]; + r[3] = a[3]; +#else + std::memmove(r, a, MP_N64 * sizeof(uint64_t)); +#endif +} + +static inline int mp_cmp(const uint64_t *a, const uint64_t *b) { +#if MP_N64 == 4 + uint64_t ai; + uint64_t bi; + + ai = a[3]; + bi = b[3]; + if (__builtin_expect(ai != bi, 1)) { + return (ai > bi) ? 1 : -1; + } + + ai = a[2]; + bi = b[2]; + if (__builtin_expect(ai != bi, 0)) { + return (ai > bi) ? 1 : -1; + } + + ai = a[1]; + bi = b[1]; + if (__builtin_expect(ai != bi, 0)) { + return (ai > bi) ? 1 : -1; + } + + ai = a[0]; + bi = b[0]; + if (__builtin_expect(ai != bi, 0)) { + return (ai > bi) ? 1 : -1; + } + + return 0; +#else + for (int i = MP_N64 - 1; i >= 0; --i) { + if (a[i] < b[i]) return -1; + if (a[i] > b[i]) return 1; + } + + return 0; +#endif +} + +static inline void mp_shl(uint64_t *r, const uint64_t *a, uint64_t k) { + if (k >= (uint64_t)MP_N64 * 64u) { + mp_zero(r); + return; + } + if (k == 0) { + mp_copy(r, a); + return; + } + + const auto wordShift = (uint32_t)(k >> 6); + const auto bitShift = (uint32_t)(k & 63u); + + if (bitShift == 0) { + for (int i = MP_N64 - 1; i >= 0; --i) { + int si = i - (int)wordShift; + r[i] = si >= 0 ? a[si] : 0; + } + return; + } + + const uint32_t inv = 64u - bitShift; + for (int i = MP_N64 - 1; i >= 0; --i) { + int si0 = i - (int)wordShift; + int si1 = si0 - 1; + + uint64_t lo = (si0 >= 0) ? a[si0] : 0; + uint64_t hi = (si1 >= 0) ? a[si1] : 0; + + r[i] = lo << bitShift | hi >> inv; + } +} + +static inline void mp_shr(uint64_t *r, const uint64_t *a, uint64_t k) { + if (k >= (uint64_t)MP_N64 * 64u) { + mp_zero(r); + return; + } + if (k == 0) { + mp_copy(r, a); + return; + } + + const auto wordShift = (uint32_t)(k >> 6); + const auto bitShift = (uint32_t)(k & 63u); + + if (bitShift == 0) { + for (uint32_t i = 0; i < MP_N64; ++i) { + uint32_t si = i + wordShift; + r[i] = (si < (uint32_t)MP_N64) ? a[si] : 0; + } + return; + } + + const uint32_t inv = 64u - bitShift; + for (uint32_t i = 0; i < MP_N64; ++i) { + uint32_t si0 = i + wordShift; + uint32_t si1 = si0 + 1; + + uint64_t lo = (si0 < (uint32_t)MP_N64) ? a[si0] : 0; + uint64_t hi = (si1 < (uint32_t)MP_N64) ? a[si1] : 0; + + r[i] = lo >> bitShift | hi << inv; + } +} + +static inline void mp_and(uint64_t *r, const uint64_t *a, const uint64_t *b) { +#if MP_N64 == 4 + r[0] = a[0] & b[0]; + r[1] = a[1] & b[1]; + r[2] = a[2] & b[2]; + r[3] = a[3] & b[3]; +#else + for (int i = 0; i < MP_N64; i++) r[i] = a[i] & b[i]; +#endif +} + +static inline void mp_or(uint64_t *r, const uint64_t *a, const uint64_t *b) { +#if MP_N64 == 4 + r[0] = a[0] | b[0]; + r[1] = a[1] | b[1]; + r[2] = a[2] | b[2]; + r[3] = a[3] | b[3]; +#else + for (int i = 0; i < MP_N64; i++) r[i] = a[i] | b[i]; +#endif +} + +static inline void mp_xor(uint64_t *r, const uint64_t *a, const uint64_t *b) { +#if MP_N64 == 4 + r[0] = a[0] ^ b[0]; + r[1] = a[1] ^ b[1]; + r[2] = a[2] ^ b[2]; + r[3] = a[3] ^ b[3]; +#else + for (int i = 0; i < MP_N64; i++) r[i] = a[i] ^ b[i]; +#endif +} + +static inline void mp_not(uint64_t *r, const uint64_t *a) { +#if MP_N64 == 4 + r[0] = ~a[0]; + r[1] = ~a[1]; + r[2] = ~a[2]; + r[3] = ~a[3]; +#else + for (int i = 0; i < MP_N64; i++) r[i] = ~a[i]; +#endif +} + +static inline bool mp_tstbit(const uint64_t *a, size_t bit) { + if (bit >= (size_t)MP_N64 * 64u) return false; + return a[bit >> 6] >> (bit & 63u) & 1ULL; +} + +void mp_set(uint64_t *r, uint64_t a); +bool mp_is_zero(const uint64_t *a); + +uint64_t mp_add(uint64_t *r, const uint64_t *a, const uint64_t *b); +uint64_t mp_add(uint64_t *r, const uint64_t *a, size_t an, const uint64_t *b, size_t bn); +uint64_t mp_sub(uint64_t *r, const uint64_t *a, const uint64_t *b); + +uint64_t mp_add(uint64_t *r, const uint64_t *a, uint64_t b); +uint64_t mp_sub(uint64_t *r, const uint64_t *a, uint64_t b); + +uint64_t mp_mul(uint64_t *r, const uint64_t *a, uint64_t b); +uint64_t mp_addmul(uint64_t *r, const uint64_t *a, size_t n, uint64_t b); + +int32_t mp_get_int32(const mp_uint_t a); +bool mp_fits_int32(const uint64_t *a); +bool mp_set(uint64_t *r, const char *str, uint32_t base); +std::string mp_get_str(const uint64_t *a, uint32_t base); + +void mp_set_mod(uint64_t *r, int64_t a, const uint64_t *mod); +bool mp_set_mod(uint64_t *r, const char *str, uint32_t base, const uint64_t *mod); + +void mp_export_be(uint8_t *r, const uint64_t *a); +void mp_import_be(uint64_t *r, const uint8_t *a); + +void mp_div(uint64_t *q, uint64_t *r, const uint64_t *num, const uint64_t *den); +void mp_pow_mod(uint64_t *r, const uint64_t *base, const uint64_t *exp, const uint64_t *mod); +bool mp_inv_mod(uint64_t *r, const uint64_t *a, const uint64_t *mod); + +#endif diff --git a/tasksfile.js b/tasksfile.js index 1f6883b..818889f 100644 --- a/tasksfile.js +++ b/tasksfile.js @@ -6,114 +6,244 @@ function cleanAll() { function downloadGoogleTest() { sh("mkdir -p build"); - sh("wget https://github.com/google/googletest/archive/release-1.10.0.tar.gz", {cwd: "build"}); - sh("tar xzf release-1.10.0.tar.gz", {cwd: "build"}); - sh("rm release-1.10.0.tar.gz", {cwd: "build"}); + sh("wget https://github.com/google/googletest/archive/release-1.10.0.tar.gz", { cwd: "build" }); + sh("tar xzf release-1.10.0.tar.gz", { cwd: "build" }); + sh("rm release-1.10.0.tar.gz", { cwd: "build" }); } function compileGoogleTest() { - sh("g++ -Igoogletest -Igoogletest/include -c googletest/src/gtest-all.cc", {cwd: "build/googletest-release-1.10.0"}); - sh("ar -rv libgtest.a gtest-all.o",{cwd: "build/googletest-release-1.10.0"}); + sh("g++ -Igoogletest -Igoogletest/include -c googletest/src/gtest-all.cc", { + cwd: "build/googletest-release-1.10.0", + nopipe: true + }); + sh("ar -rv libgtest.a gtest-all.o", { + cwd: "build/googletest-release-1.10.0", + nopipe: true + }); +} + +function createMpSources() { + sh("mkdir -p build"); + + const renderMpHpp = + String.raw`node -e "const fs=require('fs'); const ejs=require('ejs'); const path=require('path'); const data={ n64: 4 }; const tpl=fs.readFileSync(path.join('..','src','mp.hpp.ejs'),'utf8'); const out=ejs.render(tpl, data); fs.writeFileSync('mp.hpp', out);"`; + + const renderMpCpp = + String.raw`node -e "const fs=require('fs'); const ejs=require('ejs'); const path=require('path'); const data={ n64: 4 }; const tpl=fs.readFileSync(path.join('..','src','mp.cpp.ejs'),'utf8'); const out=ejs.render(tpl, data); fs.writeFileSync('mp.cpp', out);"`; + + sh(renderMpHpp, { cwd: "build", nopipe: true }); + sh(renderMpCpp, { cwd: "build", nopipe: true }); } function createFieldSources() { - sh("node ../src/buildzqfield.js -q 21888242871839275222246405745257275088696311157297823662689037894645226208583 -n Fq", {cwd: "build"}); - sh("node ../src/buildzqfield.js -q 21888242871839275222246405745257275088548364400416034343698204186575808495617 -n Fr", {cwd: "build"}); - - if (process.platform === "darwin") { - sh("nasm -fmacho64 --prefix _ fq.asm", {cwd: "build"}); - } else if (process.platform === "linux") { - sh("nasm -felf64 fq.asm", {cwd: "build"}); - } else throw("Unsupported platform"); - - if (process.platform === "darwin") { - sh("nasm -fmacho64 --prefix _ fr.asm", {cwd: "build"}); - } else if (process.platform === "linux") { - sh("nasm -felf64 fr.asm", {cwd: "build"}); - } else throw("Unsupported platform"); + sh("mkdir -p build"); + + sh( + "node ../src/buildzqfield.js -q 21888242871839275222246405745257275088696311157297823662689037894645226208583 -n Fq", + { cwd: "build", nopipe: true } + ); + sh( + "node ../src/buildzqfield.js -q 21888242871839275222246405745257275088548364400416034343698204186575808495617 -n Fr", + { cwd: "build", nopipe: true } + ); + + if (process.platform === "linux" && process.arch === "x64") { + sh("nasm -felf64 fq.asm -o fq_asm.o", { cwd: "build", nopipe: true }); + sh("nasm -felf64 fr.asm -o fr_asm.o", { cwd: "build", nopipe: true }); + } else if (process.platform === "darwin" && process.arch === "x64") { + sh("nasm -fmacho64 --prefix _ fq.asm -o fq_asm.o", { cwd: "build", nopipe: true }); + sh("nasm -fmacho64 --prefix _ fr.asm -o fr_asm.o", { cwd: "build", nopipe: true }); + } +} + +function getIncludeFlags(extra = []) { + const flags = [ + "-Igoogletest-release-1.10.0/googletest/include", + "-I.", + ...extra + ]; + return flags.join(" "); +} + +function getFieldSourcesForTest() { + if (process.platform === "darwin" && process.arch === "arm64") { + return [ + "fq.cpp", + "fq_generic.cpp", + "fq_raw_arm64.s", + //"fq_raw_generic.cpp", + "fr.cpp", + "fr_generic.cpp", + "fr_raw_arm64.s" + //"fr_raw_generic.cpp" + ]; + } + + if (process.arch === "x64") { + const asmExists = process.platform === "linux" || process.platform === "darwin"; + if (asmExists) { + return [ + "fq.cpp", + "fq_asm.o", + "fr.cpp", + "fr_asm.o" + ]; + } + } + + return [ + "fq.cpp", + "fq_generic.cpp", + "fq_raw_generic.cpp", + "fr.cpp", + "fr_generic.cpp", + "fr_raw_generic.cpp" + ]; +} + +function getFieldSourcesForBench() { + if (process.platform === "darwin" && process.arch === "arm64") { + return [ + "fq.cpp", + "fq_generic.cpp", + "fq_raw_arm64.s", + "fr.cpp", + "fr_generic.cpp", + "fr_raw_arm64.s" + ]; + } + + if (process.arch === "x64") { + const asmExists = process.platform === "linux" || process.platform === "darwin"; + if (asmExists) { + return [ + "fq.cpp", + "fq_asm.o", + "fr.cpp", + "fr_asm.o" + ]; + } + } + + return [ + "fq.cpp", + "fq_generic.cpp", + "fq_raw_generic.cpp", + "fr.cpp", + "fr_generic.cpp", + "fr_raw_generic.cpp" + ]; +} + +function getOpenMpFlags() { + if (process.platform === "linux") { + return "-fopenmp"; + } + return ""; +} + +function getAsmDefines() { + if (process.platform === "darwin" && process.arch === "arm64") { + return "-DUSE_ASM -DARCH_ARM64"; + } + if (process.arch === "x64" && (process.platform === "darwin" || process.platform === "linux")) { + return "-DUSE_ASM -DARCH_X86_64"; + } + return ""; } function testSplitParStr() { - sh("g++" + - " -Igoogletest-release-1.10.0/googletest/include"+ - " -I."+ - " -I../src"+ - " ../c/splitparstr.cpp"+ - " ../c/splitparstr_test.cpp"+ - " googletest-release-1.10.0/libgtest.a"+ - " -pthread -std=c++11 -o splitparsestr_test", {cwd: "build", nopipe: true} - ); - sh("./splitparsestr_test", {cwd: "build", nopipe: true}); + const asmDefines = getAsmDefines(); + + const cmd = + "g++ " + + (asmDefines ? asmDefines + " " : "") + + getIncludeFlags(["-I../src"]) + + " ../c/splitparstr.cpp" + + " ../c/splitparstr_test.cpp" + + " googletest-release-1.10.0/libgtest.a" + + " -pthread -std=c++11 -o splitparsestr_test"; + + sh(cmd, { cwd: "build", nopipe: true }); + sh("./splitparsestr_test", { cwd: "build", nopipe: true }); } function testAltBn128() { - sh("g++" + - " -Igoogletest-release-1.10.0/googletest/include"+ - " -I."+ - " -I../c"+ - " ../c/naf.cpp"+ - " ../c/splitparstr.cpp"+ - " ../c/alt_bn128.cpp"+ - " ../c/alt_bn128_test.cpp"+ - " ../c/misc.cpp"+ - " fq.cpp"+ - " fq.o"+ - " fr.cpp"+ - " fr.o"+ - " googletest-release-1.10.0/libgtest.a"+ + const fieldSources = getFieldSourcesForTest().join(" "); + const asmDefines = getAsmDefines(); + + const cmd = + "g++ -O3 " + + (asmDefines ? asmDefines + " " : "") + + getIncludeFlags(["-I../c"]) + + " ../c/naf.cpp" + + " ../c/splitparstr.cpp" + + " ../c/alt_bn128.cpp" + + " ../c/alt_bn128_test.cpp" + + " ../c/misc.cpp" + + " mp.cpp" + + " " + fieldSources + + " googletest-release-1.10.0/libgtest.a" + " -o altbn128_test" + - " -fmax-errors=5 -pthread -std=c++11 -fopenmp -lgmp -g", {cwd: "build", nopipe: true} - ); - sh("./altbn128_test", {cwd: "build", nopipe: true}); -} + " -pthread -std=c++17 -g"; + sh(cmd, { cwd: "build", nopipe: true }); + sh("./altbn128_test", { cwd: "build", nopipe: true }); +} function benchMultiExpG1() { - sh("g++ -O3 -g" + - " -Igoogletest-release-1.10.0/googletest/include"+ - " -I."+ - " -I../c"+ - " ../c/naf.cpp"+ - " ../c/splitparstr.cpp"+ - " ../c/alt_bn128.cpp"+ - " ../c/misc.cpp"+ - " ../benchmark/multiexp_g1.cpp"+ - " fq.cpp"+ - " fq.o"+ - " fr.cpp"+ - " fr.o"+ - // " googletest-release-1.10.0/libgtest.a"+ - " -o multiexp_g1_benchmark" + - " -lgmp -pthread -std=c++11 -fopenmp" , {cwd: "build", nopipe: true} - ); - sh("./multiexp_g1_benchmark 16777216", {cwd: "build", nopipe: true}); + const fieldSources = getFieldSourcesForBench().join(" "); + const omp = getOpenMpFlags(); + const asmDefines = getAsmDefines(); + + const cmd = + "g++ -O3 -g " + + (asmDefines ? asmDefines + " " : "") + + getIncludeFlags(["-I../c"]) + + " ../c/naf.cpp" + + " ../c/splitparstr.cpp" + + " ../c/alt_bn128.cpp" + + " ../c/misc.cpp" + + " ../benchmark/multiexp_g1.cpp" + + " mp.cpp" + + " " + fieldSources + + " -o multiexp_g1_benchmark " + + " -pthread -std=c++11" + + (omp ? " " + omp : ""); + + sh(cmd, { cwd: "build", nopipe: true }); + sh("./multiexp_g1_benchmark 16777216", { cwd: "build", nopipe: true }); } function benchMultiExpG2() { - sh("g++" + - " -Igoogletest-release-1.10.0/googletest/include"+ - " -I."+ - " -I../c"+ - " ../c/naf.cpp"+ - " ../c/splitparstr.cpp"+ - " ../c/alt_bn128.cpp"+ - " ../c/misc.cpp"+ - " ../benchmark/multiexp_g2.cpp"+ - " fq.cpp"+ - " fq.o"+ - " fr.cpp"+ - " fr.o"+ - // " googletest-release-1.10.0/libgtest.a"+ - " -o multiexp_g2_benchmark" + - " -lgmp -pthread -std=c++11 -fopenmp" , {cwd: "build", nopipe: true} - ); - sh("./multiexp_g2_benchmark 16777216", {cwd: "build", nopipe: true}); + const fieldSources = getFieldSourcesForBench().join(" "); + const omp = getOpenMpFlags(); + const asmDefines = getAsmDefines(); + + const cmd = + "g++ -O3 -g " + + (asmDefines ? asmDefines + " " : "") + + getIncludeFlags(["-I../c"]) + + " ../c/naf.cpp" + + " ../c/splitparstr.cpp" + + " ../c/alt_bn128.cpp" + + " ../c/misc.cpp" + + " ../benchmark/multiexp_g2.cpp" + + " mp.cpp" + + " " + fieldSources + + " -o multiexp_g2_benchmark " + + " -pthread -std=c++11" + + (omp ? " " + omp : ""); + + sh(cmd, { cwd: "build", nopipe: true }); + sh("./multiexp_g2_benchmark 16777216", { cwd: "build", nopipe: true }); } cli({ cleanAll, downloadGoogleTest, compileGoogleTest, + createMpSources, createFieldSources, testSplitParStr, testAltBn128, diff --git a/test/fieldasm.js b/test/fieldasm.js index 27f2798..44be7cb 100644 --- a/test/fieldasm.js +++ b/test/fieldasm.js @@ -111,8 +111,14 @@ describe("field asm test", function () { } - generateTest(bn128r, "gl"); - generateTest(bn128r, "bn128"); + generateTest(gl, "gl"); + generateTest(bn128q, "bn128q"); + generateTest(bn128r, "bn128r"); + generateTest(bls12_381q, "bls12_381q"); + generateTest(secp256k1q, "secp256k1q"); + generateTest(secp256k1r, "secp256k1r"); + generateTest(mnt6753q, "mnt6753q"); + generateTest(mnt6753r, "mnt6753r"); }); function buildTestVector2(p, op) { diff --git a/test/tester/buildzqfieldtester.js b/test/tester/buildzqfieldtester.js index d576fbf..7a030ef 100644 --- a/test/tester/buildzqfieldtester.js +++ b/test/tester/buildzqfieldtester.js @@ -2,51 +2,85 @@ const chai = require("chai"); const assert = chai.assert; const fs = require("fs"); -var tmp = require("tmp-promise"); +const tmp = require("tmp-promise"); const path = require("path"); const util = require("util"); +const ejs = require("ejs"); const exec = util.promisify(require("child_process").exec); const buildZqField = require("../../index.js").buildZqField; module.exports = testField; -async function testField(prime, test) { +async function renderTemplate(srcPath, data) { + const tpl = await fs.promises.readFile(srcPath, "utf8"); + return ejs.render(tpl, data); +} + +async function testField(prime, test, options = {}) { tmp.setGracefulCleanup(); - const dir = await tmp.dir({prefix: "ffiasm_", unsafeCleanup: true }); + const dir = await tmp.dir({ prefix: "ffiasm_", unsafeCleanup: true }); + const useAsm = options.useAsm !== false; const source = await buildZqField(prime, "Fr"); - // console.log(dir.path); - await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8"); await fs.promises.writeFile(path.join(dir.path, "fr.hpp"), source.hpp, "utf8"); await fs.promises.writeFile(path.join(dir.path, "fr.cpp"), source.cpp, "utf8"); - - await exec(`cp ${path.join(__dirname, "tester.cpp")} ${dir.path}`); - - if (process.platform === "darwin") { - await exec("nasm -fmacho64 --prefix _ " + - ` ${path.join(dir.path, "fr.asm")}` + await fs.promises.writeFile(path.join(dir.path, "fr_element.hpp"), source.element_hpp, "utf8"); + await fs.promises.writeFile(path.join(dir.path, "fr_generic.cpp"), source.generic_cpp, "utf8"); + await fs.promises.writeFile(path.join(dir.path, "fr_raw_generic.cpp"), source.raw_generic_cpp, "utf8"); + await fs.promises.writeFile(path.join(dir.path, "fr_raw_arm64.s"), source.raw_arm64_s, "utf8"); + + const mpData = { n64: source.n64 }; + //console.log("prime bits =", prime.bitLength().toString()); + //console.log("source.n64 =", source.n64); + //console.log("mpData =", mpData); + const mpHpp = await renderTemplate(path.join(__dirname, "..", "..", "src", "mp.hpp.ejs"), mpData); + //console.log(mpHpp.match(/#define MP_N64 .*/)[0]); + const mpCpp = await renderTemplate(path.join(__dirname, "..", "..", "src", "mp.cpp.ejs"), mpData); + + await fs.promises.writeFile(path.join(dir.path, "mp.hpp"), mpHpp, "utf8"); + await fs.promises.writeFile(path.join(dir.path, "mp.cpp"), mpCpp, "utf8"); + + await exec(`cp ${path.join(__dirname, "tester.cpp")} ${dir.path}`); + + let defines = []; + let sources = [ + path.join(dir.path, "tester.cpp"), + path.join(dir.path, "mp.cpp"), + path.join(dir.path, "fr.cpp") + ]; + + /*if (useAsm && process.platform === "darwin" && process.arch === "arm64") { + defines.push("-DUSE_ASM", "-DARCH_ARM64"); + sources.push( + path.join(dir.path, "fr_generic.cpp"), + path.join(dir.path, "fr_raw_arm64.s") ); - } else if (process.platform === "linux") { - await exec("nasm -felf64 " + - ` ${path.join(dir.path, "fr.asm")}` + } else */{ + sources.push( + path.join(dir.path, "fr_generic.cpp"), + path.join(dir.path, "fr_raw_generic.cpp") ); - } else throw("Unsupported platform"); - - await exec("g++" + - ` ${path.join(dir.path, "tester.cpp")}` + - ` ${path.join(dir.path, "fr.o")}` + - ` ${path.join(dir.path, "fr.cpp")}` + - ` -o ${path.join(dir.path, "tester")}` + - " -lgmp -g" - ); + } + + const compileCmd = [ + "g++", + ...defines, + `-I${dir.path}`, + ...sources, + "-o", path.join(dir.path, "tester"), + "-std=c++17", + "-g" + ].join(" "); + + await exec(compileCmd); const inLines = []; - for (let i=0; i${path.join(dir.path, "out.tst")}`); + await exec( + `${path.join(dir.path, "tester")} <${path.join(dir.path, "in.tst")} >${path.join(dir.path, "out.tst")}` + ); const res = await fs.promises.readFile(path.join(dir.path, "out.tst"), "utf8"); const resLines = res.split("\n"); - for (let i=0; i &v) { u_int64_t a; if ((v.size()<1) || (v.size() > (Fr_N64+1))) { - printf("Invalid Size: %d - %d \n", v.size(), Fr_N64); + printf("Invalid Size: %zu - %d \n", v.size(), Fr_N64); throw std::runtime_error("Invalid number of parameters for number"); } FrElement e; @@ -91,7 +91,7 @@ void pushNumber(std::vector &v) { void callFunction(FunctionSpec fs) { if (stack.size() < fs.nOps) { - throw new std::runtime_error("Not enough elements in stack"); + throw std::runtime_error("Not enough elements in stack"); } if (fs.nOps == 1) { FrElement a = stack.back(); @@ -155,10 +155,9 @@ int main(void) // Print the elements in the stack // for (int i=0; i