/*------------------------------------------------------------------------*/ static uint32 get_prime_roots(poly_coeff_t *c, uint32 p, uint32 *roots, mpz_poly_t *tmp_poly) { /* find all nonzero roots of (N' - x^d) mod p, where d is the desired polynomial degree and N' is the transformed version of N modulo p. We throw out roots of zero because a zero root implies p divides the degree or the leading algebraic poly coefficient, and neither of these is allowed in later stages */ uint32 i, high_coeff; mpz_tdiv_r_ui(tmp_poly->coeff[0], c->trans_N, p); if (mpz_cmp_ui(tmp_poly->coeff[0], 0) == 0) { /* when p divides trans_N, only a root of zero exists, so skip this p */ return 0; } for (i = 1; i < c->degree; i++) mpz_set_ui(tmp_poly->coeff[i], 0); tmp_poly->degree = i; mpz_set_ui(tmp_poly->coeff[i], p - 1); return poly_get_zeros(roots, tmp_poly, p, &high_coeff, 0); }
int main(int argc, char *argv[]) { int poly_idx; gls_config_t cfg; fb_t fb; u_int32_t i, n_roots; u_int64_t fb_idx, fb_alloc; mpz_t P, roots[MAX_POLY_DEGREE]; u_int32_t roots_ui[MAX_POLY_DEGREE]; char fname[4096]; off_t align; int fd; if(argc < 2) { fprintf(stderr, "usage: %s <polyconfig>\n", argv[0]); return 1; } gls_config_init(cfg); if(polyfile_read(cfg, argv[1]) < 0) return 1; mpz_init(P); for(i = 0; i < sizeof(roots) / sizeof(roots[0]); i++) mpz_init(roots[i]); for(poly_idx = 0; poly_idx < POLY_CNT; poly_idx++) { fb_init(fb); fb_idx = 0; fb_alloc = 0; for(mpz_set_ui(P, 2); mpz_cmp_ui(P, MAX_SMALL_PRIME) < 0 && mpz_cmp_ui(P, cfg->lim[poly_idx]) < 0; mpz_nextprime(P, P)) { n_roots = poly_get_zeros(roots_ui, cfg->poly[poly_idx], mpz_get_ui(P), 0); if(!n_roots) continue; qsort(roots_ui, n_roots, sizeof(roots_ui[0]), ui_cmp); //#define TEST_ROOTFINDER 1 #ifdef TEST_ROOTFINDER for(i = 0; i < n_roots; i++) { mpz_t tmp1, tmp2; mpz_init_set_ui(tmp1, roots_ui[i]); mpz_init(tmp2); mpzpoly_eval_mod(tmp2, cfg->poly[poly_idx], tmp1, P); if(mpz_cmp_ui(tmp2, 0) != 0) { printf("BAD ROOT (%u,%u)\n", roots_ui[i], mpz_get_ui(P)); exit(-1); } mpz_clear(tmp1); mpz_clear(tmp2); } #endif fb->n_small += n_roots; if(fb->n_small > fb_alloc) { fb_alloc += 4096; fb->r_small = (u_int32_t *) realloc(fb->r_small, sizeof(u_int32_t) * fb_alloc); fb->p_small = (u_int32_t *) realloc(fb->p_small, sizeof(u_int32_t) * fb_alloc); if(!fb->r_small || !fb->p_small) { perror("realloc"); exit(1); } } for(i = 0; i < n_roots; i++) { fb->r_small[fb_idx] = roots_ui[i]; fb->p_small[fb_idx] = mpz_get_ui(P); fb_idx++; } } fb_idx = 0; fb_alloc = 0; for(; mpz_cmp_ui(P, cfg->lim[poly_idx]) < 0; mpz_nextprime(P, P)) { n_roots = mpzpoly_get_roots(roots, cfg->poly[poly_idx], P); if(!n_roots) continue; fb->n_large += n_roots; if(fb->n_large > fb_alloc) { fb_alloc += 4096; fb->r_large = (u_int64_t *) realloc(fb->r_large, sizeof(u_int64_t) * fb_alloc); fb->p_large = (u_int64_t *) realloc(fb->p_large, sizeof(u_int64_t) * fb_alloc); if(!fb->r_large || !fb->p_large) { perror("realloc"); exit(1); } } for(i = 0; i < n_roots; i++) { fb->r_large[fb_idx] = mpz_get_ui(roots[i]); fb->p_large[fb_idx] = mpz_get_ui(P); fb_idx++; } } memset(fname, 0, sizeof(fname)); snprintf(fname, sizeof(fname) - 1, "%s.fb.%u", argv[1], poly_idx); if(fb_filesave(fb, fname) < 0) return 1; //#define TEST_SAVELOAD 1 #ifdef TEST_SAVELOAD { fb_t fb2; fb_init(fb2); if(fb_fileread(fb2, fname) < 0) return 1; if(fb->n_small != fb2->n_small || fb->n_large != fb2->n_large) { printf("COUNT MISMATCH\n"); return 1; } if(memcmp(fb->p_small, fb2->p_small, sizeof(u_int32_t) * fb->n_small) != 0) { printf("SMALL MISMATCH\n"); return 1; } if(memcmp(fb->p_large, fb2->p_large, sizeof(u_int64_t) * fb->n_large) != 0) { printf("LARGE MISMATCH\n"); return 1; } fb_clear(fb2); } #endif fb_clear(fb); } return 0; }