/* Reference implementation of zn_array_pack(). (doesn't take into account the s or r parameters) */ void ref_zn_array_pack (mp_limb_t* res, const ulong* op, size_t n, unsigned b, unsigned k) { mpz_t x; mpz_init (x); ref_zn_array_pack_helper (x, op, n, b, k); mpz_to_mpn (res, CEIL_DIV (n * b + k, GMP_NUMB_BITS), x); mpz_clear (x); }
/* tests zn_array_unpack() once for given n, b, k */ int testcase_zn_array_unpack (size_t n, unsigned b, unsigned k) { size_t buf_size = CEIL_DIV (n * b + k, GMP_NUMB_BITS); size_t size = n * CEIL_DIV (b, ULONG_BITS); mp_limb_t* buf = (mp_limb_t*) malloc (sizeof (mp_limb_t) * buf_size); ulong* res = (ulong*) malloc (sizeof (ulong) * (size + 2)); ulong* ref = (ulong*) malloc (sizeof (ulong) * (size + 2)); // sentries to check buffer overflow res[0] = res[size + 1] = ref[0] = ref[size + 1] = 0x1234; // generate random data mpz_t x; mpz_init (x); mpz_urandomb (x, randstate, n * b); mpz_mul_2exp (x, x, k); mpz_to_mpn (buf, buf_size, x); mpz_clear (x); // run target and reference implementation zn_array_unpack (res + 1, buf, n, b, k); ref_zn_array_unpack (ref + 1, buf, n, b, k); int success = 1; // check sentries success = success && (res[0] == 0x1234); success = success && (ref[0] == 0x1234); success = success && (res[size + 1] == 0x1234); success = success && (ref[size + 1] == 0x1234); // check correct result success = success && (zn_array_cmp (res + 1, ref + 1, size) == 0); free (ref); free (res); free (buf); return success; }
int main (int argc, char **argv) { gmp_randstate_ptr rands; long count = COUNT; mp_ptr mp; mp_ptr ap; mp_ptr tp; mp_ptr scratch; mpz_t m, a, r, g; int test; mp_limb_t ran; mp_size_t itch; TMP_DECL; tests_start (); rands = RANDS; TMP_MARK; mpz_init (m); mpz_init (a); mpz_init (r); mpz_init (g); if (argc > 1) { char *end; count = strtol (argv[1], &end, 0); if (*end || count <= 0) { fprintf (stderr, "Invalid test count: %s.\n", argv[1]); return 1; } } mp = TMP_ALLOC_LIMBS (MAX_SIZE); ap = TMP_ALLOC_LIMBS (MAX_SIZE); tp = TMP_ALLOC_LIMBS (MAX_SIZE); scratch = TMP_ALLOC_LIMBS (mpn_sec_invert_itch (MAX_SIZE) + 1); for (test = 0; test < count; test++) { mp_bitcnt_t bits; int rres, tres; mp_size_t n; bits = urandom () % (GMP_NUMB_BITS * MAX_SIZE) + 1; if (test & 1) mpz_rrandomb (m, rands, bits); else mpz_urandomb (m, rands, bits); if (test & 2) mpz_rrandomb (a, rands, bits); else mpz_urandomb (a, rands, bits); mpz_setbit (m, 0); if (test & 4) { /* Ensure it really is invertible */ if (mpz_sgn (a) == 0) mpz_set_ui (a, 1); else for (;;) { mpz_gcd (g, a, m); if (mpz_cmp_ui (g, 1) == 0) break; mpz_remove (a, a, g); } } rres = mpz_invert (r, a, m); if ( (test & 4) && !rres) { gmp_fprintf (stderr, "test %d: Not invertible!\n" "m = %Zd\n" "a = %Zd\n", test, m, a); abort (); } ASSERT_ALWAYS (! (test & 4) || rres); n = (bits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; ASSERT_ALWAYS (n <= MAX_SIZE); itch = mpn_sec_invert_itch (n); scratch[itch] = ran = urandom (); mpz_to_mpn (ap, n, a); mpz_to_mpn (mp, n, m); tres = mpn_sec_invert (tp, ap, mp, n, bit_size (ap, n) + bit_size (mp, n), scratch); if (rres != tres || (rres == 1 && !mpz_eq_mpn (tp, n, r)) || ran != scratch[itch]) { gmp_fprintf (stderr, "Test %d failed.\n" "m = %Zd\n" "a = %Zd\n", test, m, a); fprintf (stderr, "ref ret: %d\n" "got ret: %d\n", rres, tres); if (rres) gmp_fprintf (stderr, "ref: %Zd\n", r); if (tres) gmp_fprintf (stderr, "got: %Nd\n", tp, n); if (ran != scratch[itch]) fprintf (stderr, "scratch[itch] changed.\n"); abort (); } } TMP_FREE; mpz_clear (m); mpz_clear (a); mpz_clear (r); mpz_clear (g); tests_end (); return 0; }
int test__ZmodF_mul_threeway_reduce() { int success = 1; mp_limb_t in[2000]; mp_limb_t out1[2000]; mp_limb_t out2[2000]; mp_limb_t test[2000]; mpz_t x, y, power, power2, mod1, mod2; mpz_init(x); mpz_init(y); mpz_init(power); mpz_init(power2); mpz_init(mod1); mpz_init(mod2); for (unsigned long n = 3; n < 300 && success; n += 3) { #if DEBUG printf("n = %d\n", n); #endif // power = B^n mpz_set_ui(power, 1); mpz_mul_2exp(power, power, n*FLINT_BITS); // power2 = B^(2n/3) mpz_set_ui(power2, 1); mpz_mul_2exp(power2, power2, 2*n/3*FLINT_BITS); // mod1 = B^(n/3) + 1 mpz_set_ui(mod1, 1); mpz_mul_2exp(mod1, mod1, n/3*FLINT_BITS); mpz_add_ui(mod1, mod1, 1); // mod2 = B^(2n/3) - B^(n/3) + 1 mpz_set(mod2, mod1); mpz_mul_2exp(mod2, mod2, n/3*FLINT_BITS); mpz_sub(mod2, mod2, mod1); mpz_sub(mod2, mod2, mod1); mpz_add_ui(mod2, mod2, 3); for (unsigned long trial = 0; trial < 250 && success; trial++) { random_limbs(in, n); in[n] = 0; mpn_to_mpz(x, in, n+1); _ZmodF_mul_threeway_reduce1(out1, in, n/3); ZmodF_normalise(out1, n/3); mpz_mod(y, x, mod1); mpz_to_mpn(test, n/3 + 1, y); if (mpn_cmp(test, out1, n/3 + 1)) success = 0; _ZmodF_mul_threeway_reduce2(out2, in, n/3); mpz_mod(y, x, mod2); mpz_to_mpn(test, 2*n/3, y); if (mpn_cmp(test, out2, 2*n/3)) { // didn't work... check if the "other answer" is correct mpz_add(y, y, mod2); if (mpz_cmp(y, power2) >= 0) success = 0; else { mpz_to_mpn(test, 2*n/3, y); if (mpn_cmp(test, out2, 2*n/3)) success = 0; } } } } mpz_clear(mod2); mpz_clear(mod1); mpz_clear(power2); mpz_clear(power); mpz_clear(y); mpz_clear(x); return success; }
int test__ZmodF_mul_fft_combine() { int success = 1; mpz_t x, y, p, q, r, s, total; mpz_init(x); mpz_init(y); mpz_init(s); mpz_init(r); mpz_init(q); mpz_init(p); mpz_init(total); mp_limb_t buf[300]; for (unsigned long n = 1; n < 80 && success; n++) { for (unsigned long depth = 0; ((n*FLINT_BITS) % (1 << depth) == 0) && success; depth++) { for (unsigned long m = 1; m < n/4 && success; m++) { for (unsigned long k = 0; k < 5 && success; k++) { #if DEBUG printf("n = %ld, depth = %ld, m = %ld, k = %ld\n", n, depth, m, k); #endif ZmodF_poly_t poly; ZmodF_poly_init(poly, depth, m+k, 1); // p := B^n + 1 mpz_set_ui(p, 1); mpz_mul_2exp(p, p, n*FLINT_BITS); mpz_add_ui(p, p, 1); // q := (B^m + 1)*B^k mpz_set_ui(q, 1); mpz_mul_2exp(q, q, m*FLINT_BITS); mpz_add_ui(q, q, 1); mpz_mul_2exp(q, q, k*FLINT_BITS); // r := B^(m+k) - 1 mpz_set_ui(r, 1); mpz_mul_2exp(r, r, (m+k)*FLINT_BITS); mpz_sub_ui(r, r, 1); // s := B^(m+k)/2 mpz_set_ui(s, 1); mpz_mul_2exp(s, s, (m+k)*FLINT_BITS - 1); for (unsigned long trial = 0; trial < 20 && success; trial++) { mpz_set_ui(total, 0); for (long i = (1 << depth) - 1; i >= 0; i--) { // select random x in (0, B^(m+k)) mpz_set_ui(x, 0); while (!mpz_sgn(x)) { mpz_rrandomb(x, randstate, (m+k)*FLINT_BITS); if (random_ulong(2)) // to get high bit 0 sometimes mpz_sub(x, r, x); } // push it down to (-B^(m+k)/2, B^(m+k)/2) mpz_sub(x, x, s); // add it to running total mpz_mul_2exp(total, total, (n*FLINT_BITS) >> depth); mpz_add(total, total, x); // normalise it into [0, q), and store in polynomial mpz_mod(x, x, q); mpz_to_mpn(poly->coeffs[i], m+k+1, x); } // compare result to target function _ZmodF_mul_fft_combine(buf, poly, m, k, n); ZmodF_normalise(buf, n); mpn_to_mpz(y, buf, n+1); mpz_mod(total, total, p); if (mpz_cmp(total, y)) success = 0; } ZmodF_poly_clear(poly); } } } } mpz_clear(x); mpz_clear(y); mpz_clear(s); mpz_clear(r); mpz_clear(q); mpz_clear(p); mpz_clear(total); return success; }