4 #include <mLib/alloc.h>
13 /*----- Polynomials over finite fields ------------------------------------*/
20 #define POLY_INIT { 0, 0, 0 }
22 #define POLY_ZEROP(p) (!(p)->len)
23 #define POLY_CONSTANTP(p) ((p)->len == 1)
24 #define POLY_DEGREE(p) ((p)->len - 1)
26 void poly_free(poly
*p
)
30 for (i
= 0; i
< p
->sz
; i
++)
32 xfree(p
->v
); p
->v
= 0;
36 void poly_ensure(field
*f
, poly
*p
, unsigned sz
)
44 n
= p
->sz
; if (!n
) n
= 2; do n
<<= 1; while (n
< sz
);
45 x
= xmalloc(n
* sizeof(mp
*));
46 for (i
= 0; i
< p
->sz
; i
++)
49 x
[i
] = MP_COPY(f
->zero
);
55 void poly_fix(field
*f
, poly
*p
, unsigned n
)
57 while (n
&& F_ZEROP(f
, p
->v
[n
- 1]))
62 #define MAX(a, b) ((a) > (b) ? (a) : (b))
64 static void putmphex(field
*f
, const char *name
, mp
*x
)
68 printf("%s = 0x", name
);
69 z
= F_OUT(f
, MP_NEW
, x
);
70 mp_writefile(z
, stdout
, 16);
75 void poly_dump(field
*f
, const char *name
, poly
*p
)
80 printf("%s = (", name
);
81 for (i
= p
->len
; i
--; ) {
83 z
= F_OUT(f
, z
, p
->v
[i
]);
84 mp_writefile(z
, stdout
, 16);
91 void poly_add(field
*f
, poly
*d
, poly
*x
, poly
*y
)
94 unsigned n
= MAX(x
->len
, y
->len
);
96 /* poly_dump(f, "add x", x); */
97 /* poly_dump(f, "add y", y); */
99 for (i
= 0; i
< n
; i
++) {
100 mp
*a
= (i
< x
->len
) ? x
->v
[i
] : f
->zero
;
101 mp
*b
= (i
< y
->len
) ? y
->v
[i
] : f
->zero
;
102 d
->v
[i
] = F_ADD(f
, d
->v
[i
], a
, b
);
105 /* poly_dump(f, "add d", d); */
108 void poly_sub(field
*f
, poly
*d
, poly
*x
, poly
*y
)
111 unsigned n
= MAX(x
->len
, y
->len
);
113 /* poly_dump(f, "sub x", x); */
114 /* poly_dump(f, "sub y", y); */
115 poly_ensure(f
, d
, n
);
116 for (i
= 0; i
< n
; i
++) {
117 mp
*a
= (i
< x
->len
) ? x
->v
[i
] : f
->zero
;
118 mp
*b
= (i
< y
->len
) ? y
->v
[i
] : f
->zero
;
119 d
->v
[i
] = F_SUB(f
, d
->v
[i
], a
, b
);
122 /* poly_dump(f, "sub d", d); */
125 static void omuladd(field
*f
, poly
*x
, poly
*y
, mp
*z
, unsigned o
)
128 unsigned n
= MAX(x
->len
, y
->len
+ o
);
131 /* poly_dump(f, "omuladd x", x); */
132 /* poly_dump(f, "omuladd y", y); */
133 /* putmphex(f, "omuladd z", z); */
134 /* printf("omuladd o = %u\n", o); */
135 poly_ensure(f
, x
, n
);
136 for (i
= o
; i
< n
; i
++) {
137 if (i
< y
->len
+ o
) {
138 mp
*a
= (i
< x
->len
) ? x
->v
[i
] : f
->zero
;
139 t
= F_MUL(f
, t
, y
->v
[i
- o
], z
);
140 x
->v
[i
] = F_ADD(f
, x
->v
[i
], a
, t
);
145 /* poly_dump(f, "omuladd d", x); */
148 static void omulsub(field
*f
, poly
*x
, poly
*y
, mp
*z
, unsigned o
)
151 unsigned n
= MAX(x
->len
, y
->len
+ o
);
154 /* poly_dump(f, "omulsub x", x); */
155 /* poly_dump(f, "omulsub y", y); */
156 /* putmphex(f, "omulsub z", z); */
157 /* printf("omulsub o = %u\n", o); */
158 poly_ensure(f
, x
, n
);
159 for (i
= o
; i
< n
; i
++) {
160 if (i
< y
->len
+ o
) {
161 mp
*a
= (i
< x
->len
) ? x
->v
[i
] : f
->zero
;
162 t
= F_MUL(f
, t
, y
->v
[i
- o
], z
);
163 x
->v
[i
] = F_SUB(f
, x
->v
[i
], a
, t
);
168 /* poly_dump(f, "omulsub d", x); */
171 void poly_mul(field
*f
, poly
*d
, poly
*x
, poly
*y
)
176 /* poly_dump(f, "mul x", x); */
177 /* poly_dump(f, "mul y", y); */
178 poly_ensure(f
, &dd
, x
->len
+ y
->len
);
179 for (i
= 0; i
< y
->len
; i
++) {
180 if (!F_ZEROP(f
, y
->v
[i
]))
181 omuladd(f
, &dd
, x
, y
->v
[i
], i
);
185 /* poly_dump(f, "mul d", d); */
188 void poly_copy(field
*f
, poly
*d
, poly
*p
)
192 poly_ensure(f
, d
, p
->len
);
193 for (i
= 0; i
< p
->len
; i
++) {
195 d
->v
[i
] = MP_COPY(p
->v
[i
]);
200 void poly_div(field
*f
, poly
*q
, poly
*r
, poly
*x
, poly
*y
)
202 poly qq
= POLY_INIT
, rr
= POLY_INIT
;
208 /* poly_dump(f, "div x", x); */
209 /* poly_dump(f, "div y", y); */
211 i
= F_INV(f
, MP_NEW
, y
->v
[y
->len
- 1]);
212 poly_copy(f
, &rr
, x
);
213 if (rr
.len
>= y
->len
) {
214 o
= oo
= rr
.len
- y
->len
+ 1;
216 if (q
) poly_ensure(f
, &qq
, o
);
219 if (!F_ZEROP(f
, rr
.v
[j
])) {
220 z
= F_MUL(f
, z
, rr
.v
[j
], i
);
221 if (q
) qq
.v
[o
] = MP_COPY(z
);
222 omulsub(f
, &rr
, y
, z
, o
);
227 poly_fix(f
, &qq
, oo
);
230 /* poly_dump(f, "div q", q); */
232 /* poly_dump(f, "div r", &rr); */
243 void poly_monic(field
*f
, poly
*d
, poly
*p
)
250 /* poly_dump(f, "monic p", p); */
251 poly_ensure(f
, d
, n
);
252 z
= F_INV(f
, MP_NEW
, p
->v
[n
- 1]);
253 for (i
= 0; i
< n
; i
++)
254 d
->v
[i
] = F_MUL(f
, d
->v
[i
], p
->v
[i
], z
);
256 /* poly_dump(f, "monic d", d); */
260 void poly_gcd(field
*f
, poly
*g
, poly
*x
, poly
*y
)
262 poly uu
= POLY_INIT
, vv
= POLY_INIT
, rr
= POLY_INIT
;
263 poly
*u
= &uu
, *v
= &vv
, *r
= &rr
;
266 /* poly_dump(f, "gcd x", x); */
267 /* poly_dump(f, "gcd y", y); */
268 poly_copy(f
, u
, x
); poly_copy(f
, v
, y
);
269 if (u
->len
< v
->len
) { t
= u
; u
= v
; v
= t
; }
270 while (!POLY_ZEROP(v
)) {
271 poly_div(f
, 0, r
, u
, v
);
272 t
= u
; u
= v
; v
= r
; r
= t
;
278 /* poly_dump(f, "gcd g", g); */
281 mp
*poly_solve(field
*f
, mp
*d
, mp
*p
, grand
*r
)
288 unsigned m
= f
->nbits
;
291 poly_ensure(f
, &g
, m
+ 1);
292 for (i
= 0; i
<= m
; i
++)
293 g
.v
[i
] = mp_testbit(p
, i
) ?
MP_COPY(f
->one
) : MP_COPY(f
->zero
);
294 poly_fix(f
, &g
, m
+ 1);
295 poly_ensure(f
, &ut
, 2);
296 while (POLY_DEGREE(&g
) > 1) {
297 ut
.v
[1] = mprand(ut
.v
[1], m
, r
, 0);
299 poly_copy(f
, &c
, &ut
);
300 /* poly_dump(f, "c-in", &c); */
302 for (i
= 1; i
< m
; i
++) {
303 poly_mul(f
, &c
, &c
, &c
);
304 poly_add(f
, &c
, &c
, &ut
);
305 poly_div(f
, 0, &c
, &c
, &g
);
306 /* putchar('.'); fflush(stdout); */
308 /* poly_dump(f, "c-out", &c); */
309 poly_gcd(f
, &h
, &c
, &g
);
310 /* poly_dump(f, "h", &h); */
311 if (POLY_CONSTANTP(&h
) || POLY_DEGREE(&h
) == POLY_DEGREE(&g
))
313 if (2 * POLY_DEGREE(&h
) > POLY_DEGREE(&g
))
314 poly_div(f
, &g
, 0, &g
, &h
);
316 poly_copy(f
, &g
, &h
);
327 /*----- Other stuff -------------------------------------------------------*/
329 static int primep(unsigned x
)
333 for (i
= 2; i
*i
< x
; i
++) {
340 static unsigned gcd(unsigned u
, unsigned v
)
344 if (u
< v
) { r
= u
; u
= v
; v
= r
; }
352 static int onbtype(unsigned m
)
360 for (t
= 1; t
<= 2; t
++) {
364 for (x
= 2, k
= 1; x
!= 1; x
= (2*x
)%p
, k
++);
373 static mp
*fieldpoly(unsigned m
, int t
)
381 for (i
= 0; i
<= m
; i
++)
382 p
= mp_setbit(p
, p
, i
);
388 for (i
= 1; i
< m
; i
++) {
391 z
= r
; r
= q
; q
= p
; p
= z
;
402 static int dofip(unsigned m
, mp
**p
, unsigned n
, unsigned x
)
406 for (i
= n
+ 1; i
< x
; i
++) {
407 *p
= mp_setbit(*p
, *p
, i
);
408 if (n ?
dofip(m
, p
, n
- 1, i
) : gf_irreduciblep(*p
))
410 *p
= mp_clearbit(*p
, *p
, i
);
415 static mp
*fip(unsigned m
)
420 p
= mp_setbit(p
, p
, m
);
422 while (!dofip(m
, &p
, n
, m
))
427 static mp
*fnb(mp
*p
)
431 grand
*r
= fibrand_create(0);
433 unsigned m
= mp_bits(p
) - 1;
435 if ((t
= onbtype(m
)) == 0)
437 f
= field_binpoly(p
);
439 x
= poly_solve(f
, MP_NEW
, q
, r
);
445 int main(int argc
, char *argv
[])
447 int m
= atoi(argv
[1]);
456 p
= mp_setbit(p
, p
, m
);
457 for (i
= 2; i
< argc
; i
++)
458 p
= mp_setbit(p
, p
, atoi(argv
[i
]));
460 if (!gf_irreduciblep(p
)) {
461 printf("not irreducible\n");
466 for (i
= m
+ 1; i
--; ) {
467 if (mp_testbit(p
, i
))
476 MP_PRINTX("beta", beta
);
480 assert(mparena_count(MPARENA_GLOBAL
) == 0);