1 /*
2     Copyright (C) 2013 Mike Hansen
3 
4     This file is part of FLINT.
5 
6     FLINT is free software: you can redistribute it and/or modify it under
7     the terms of the GNU Lesser General Public License (LGPL) as published
8     by the Free Software Foundation; either version 2.1 of the License, or
9     (at your option) any later version.  See <https://www.gnu.org/licenses/>.
10 */
11 
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include "flint.h"
16 #include "fq_zech.h"
17 
18 void
fq_zech_ctx_init(fq_zech_ctx_t ctx,const fmpz_t p,slong d,const char * var)19 fq_zech_ctx_init(fq_zech_ctx_t ctx, const fmpz_t p, slong d, const char *var)
20 {
21     if (!_fq_zech_ctx_init_conway(ctx, p, d, var))
22         fq_zech_ctx_init_random(ctx, p, d, var);
23 }
24 
25 void
fq_zech_ctx_init_conway(fq_zech_ctx_t ctx,const fmpz_t p,slong d,const char * var)26 fq_zech_ctx_init_conway(fq_zech_ctx_t ctx, const fmpz_t p, slong d,
27                         const char *var)
28 {
29     fq_nmod_ctx_struct * fq_nmod_ctx;
30 
31     fq_nmod_ctx = flint_malloc(sizeof(fq_nmod_ctx_struct));
32 
33     fq_nmod_ctx_init_conway(fq_nmod_ctx, p, d, var);
34     fq_zech_ctx_init_fq_nmod_ctx(ctx, fq_nmod_ctx);
35     ctx->owns_fq_nmod_ctx = 1;
36     ctx->is_conway = 1;
37 }
38 
39 int
_fq_zech_ctx_init_conway(fq_zech_ctx_t ctx,const fmpz_t p,slong d,const char * var)40 _fq_zech_ctx_init_conway(fq_zech_ctx_t ctx, const fmpz_t p, slong d,
41                          const char *var)
42 {
43     int result;
44     fq_nmod_ctx_struct * fq_nmod_ctx;
45 
46     fq_nmod_ctx = flint_malloc(sizeof(fq_nmod_ctx_struct));
47 
48     result = _fq_nmod_ctx_init_conway(fq_nmod_ctx, p, d, var);
49     if (!result)
50     {
51         flint_free(fq_nmod_ctx);
52 	ctx->is_conway = 0;
53         return result;
54     } else
55         ctx->is_conway = 1;
56 
57     fq_zech_ctx_init_fq_nmod_ctx(ctx, fq_nmod_ctx);
58     ctx->owns_fq_nmod_ctx = 1;
59     return result;
60 }
61 
62 void
fq_zech_ctx_init_random(fq_zech_ctx_t ctx,const fmpz_t p,slong d,const char * var)63 fq_zech_ctx_init_random(fq_zech_ctx_t ctx, const fmpz_t p, slong d,
64                         const char *var)
65 {
66     fq_nmod_ctx_struct * fq_nmod_ctx;
67     flint_rand_t state;
68     nmod_poly_t poly;
69 
70     fq_nmod_ctx = flint_malloc(sizeof(fq_nmod_ctx_struct));
71 
72     flint_randinit(state);
73 
74     nmod_poly_init2(poly, fmpz_get_ui(p), d + 1);
75     nmod_poly_randtest_monic_primitive(poly, state, d + 1);
76 
77     fq_nmod_ctx_init_modulus(fq_nmod_ctx, poly, var);
78 
79     nmod_poly_clear(poly);
80     flint_randclear(state);
81 
82     fq_zech_ctx_init_fq_nmod_ctx(ctx, fq_nmod_ctx);
83     ctx->owns_fq_nmod_ctx = 1;
84     ctx->is_conway = 0;
85 }
86 
87 int
fq_zech_ctx_init_modulus_check(fq_zech_ctx_t ctx,const nmod_poly_t modulus,const char * var)88 fq_zech_ctx_init_modulus_check(fq_zech_ctx_t ctx,
89                          const nmod_poly_t modulus,
90                          const char *var)
91 {
92     int primitive;
93     fq_nmod_ctx_struct * fq_nmod_ctx;
94 
95     fq_nmod_ctx = flint_malloc(sizeof(fq_nmod_ctx_struct));
96 
97     fq_nmod_ctx_init_modulus(fq_nmod_ctx, modulus, var);
98     primitive = fq_zech_ctx_init_fq_nmod_ctx_check(ctx, fq_nmod_ctx);
99     ctx->owns_fq_nmod_ctx = 1;
100     return primitive;
101 }
102 
103 void
fq_zech_ctx_init_modulus(fq_zech_ctx_t ctx,const nmod_poly_t modulus,const char * var)104 fq_zech_ctx_init_modulus(fq_zech_ctx_t ctx,
105 		   const nmod_poly_t modulus,
106 		   const char *var)
107 {
108    fq_zech_ctx_init_modulus_check(ctx, modulus, var);
109 }
110 
111 int
fq_zech_ctx_init_fq_nmod_ctx_check(fq_zech_ctx_t ctx,fq_nmod_ctx_t fq_nmod_ctx)112 fq_zech_ctx_init_fq_nmod_ctx_check(fq_zech_ctx_t ctx,
113                              fq_nmod_ctx_t fq_nmod_ctx)
114 {
115     ulong i, n;
116     fq_nmod_t r, gen;
117     slong up, q;
118     fmpz_t result, order;
119     mp_limb_t j, nz, result_ui;
120     mp_limb_t *n_reverse_table;
121 
122     ctx->fq_nmod_ctx = fq_nmod_ctx;
123     ctx->owns_fq_nmod_ctx = 0;
124 
125     fmpz_init(order);
126     fq_nmod_ctx_order(order, fq_nmod_ctx);
127 
128     if (fmpz_bits(order) > FLINT_BITS)
129     {
130         flint_printf("Exception (fq_zech_ctx_init_fq_nmod_ctx). Requires q < 2^FLINT_BITS\n");
131         flint_abort();
132     }
133 
134     q = fmpz_get_ui(order);
135     up = fmpz_get_ui(fq_nmod_ctx_prime(fq_nmod_ctx));
136 
137     ctx->p = up;
138     ctx->ppre = n_precompute_inverse(ctx->p);
139     ctx->qm1 = q - 1;
140 
141     if (up == 2)
142     {
143         ctx->qm1o2 = 0;
144     }
145     else
146     {
147         ctx->qm1o2 = ctx->qm1 / 2;
148     }
149 
150     ctx->qm1opm1 = ctx->qm1 / (up - 1);
151 
152 /* 1. The field may not be defined with a Conway polynomial
153  * 2. need to ensure prime_root is the norm of the generator
154  * 3. so we take prime_root = (-1)^d * a_0, where d is the degree
155  *    of the minimum polynomial P of the generator, and a_0 is the constant term of
156  *    the generator.
157  * 4. this is because if P(t) = (t-x_0)...(t-x_{d-1}), then the constant term of
158  * P is the product of the x_i (ie the norm) and is equal to (-1)^d * a_0
159  */
160     ctx->prime_root = (fq_nmod_ctx_degree(fq_nmod_ctx) & 1) ?
161         ctx->p - fq_nmod_ctx->a[0] : fq_nmod_ctx->a[0];
162 
163     ctx->zech_log_table = (mp_limb_t *) flint_malloc(q * sizeof(mp_limb_t));
164     ctx->prime_field_table = (mp_limb_t *) flint_malloc(up * sizeof(mp_limb_t));
165     n_reverse_table = (mp_limb_t *) flint_malloc(q * sizeof(mp_limb_t));
166     ctx->eval_table = (mp_limb_t *) flint_malloc(q * sizeof(mp_limb_t));
167 
168     ctx->zech_log_table[ctx->qm1] = 0;
169     ctx->prime_field_table[0] = ctx->qm1;
170     for (i = 0; i < q; i++)
171         n_reverse_table[i] = ctx->qm1;
172     ctx->eval_table[ctx->qm1] = 0;
173 
174     fq_nmod_init(r, ctx->fq_nmod_ctx);
175     fq_nmod_init(gen, ctx->fq_nmod_ctx);
176     fq_nmod_one(r, ctx->fq_nmod_ctx);
177     fq_nmod_gen(gen, ctx->fq_nmod_ctx);
178 
179     fmpz_init(result);
180 
181     for (i = 0; i < ctx->qm1; i++)
182     {
183         nmod_poly_evaluate_fmpz(result, r, fq_nmod_ctx_prime(fq_nmod_ctx));
184         result_ui = fmpz_get_ui(result);
185         if (n_reverse_table[result_ui] != ctx->qm1)
186             return 0; /* failure: modulus not primitive */
187         n_reverse_table[result_ui] = i;
188         ctx->eval_table[i] = result_ui;
189         if (r->length == 1)
190         {
191             ctx->prime_field_table[result_ui] = i;
192         }
193         fq_nmod_mul(r, r, gen, fq_nmod_ctx);
194     }
195 
196     i = 1;
197     for (i = 0; i < q; i++)
198     {
199         j = n_reverse_table[i];
200         n = i;
201         if (n % up == up - 1)
202         {
203             nz = n - up + 1;
204         }
205         else
206         {
207             nz = n + 1;
208         }
209         ctx->zech_log_table[j] = n_reverse_table[nz];
210     }
211 
212     fq_nmod_clear(r, fq_nmod_ctx);
213     fq_nmod_clear(gen, fq_nmod_ctx);
214     flint_free(n_reverse_table);
215     fmpz_clear(result);
216     fmpz_clear(order);
217 
218     return 1; /* success */
219 }
220 
221 void
fq_zech_ctx_init_fq_nmod_ctx(fq_zech_ctx_t ctx,fq_nmod_ctx_t fq_nmod_ctx)222 fq_zech_ctx_init_fq_nmod_ctx(fq_zech_ctx_t ctx, fq_nmod_ctx_t fq_nmod_ctx)
223 {
224     if (!fq_zech_ctx_init_fq_nmod_ctx_check(ctx, fq_nmod_ctx))
225     {
226         flint_printf("Exception (fq_zech_ctx_init_fq_nmod_ctx). Polynomial is not primitive.\n");
227 	flint_abort();
228     }
229 }
230