Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
#ifndef _FFEXT_INCLUDE_
2
#define _FFEXT_INCLUDE_
3
4
#include "mpzutil.h" // ui_randomm
5
#include "ffwrapper.h"
6
7
/*
8
Copyright 2008 Andrew V. Sutherland
9
10
This file is part of smalljac.
11
12
smalljac is free software: you can redistribute it and/or modify
13
it under the terms of the GNU General Public License as published by
14
the Free Software Foundation, either version 2 of the License, or
15
(at your option) any later version.
16
17
smalljac is distributed in the hope that it will be useful,
18
but WITHOUT ANY WARRANTY; without even the implied warranty of
19
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
GNU General Public License for more details.
21
22
You should have received a copy of the GNU General Public License
23
along with smalljac. If not, see <http://www.gnu.org/licenses/>.
24
*/
25
26
// subset of finite field arithmetic supported in degree 2 and 3 extension fields
27
// elements are represented as polys over F_p[x]/(g(x)) where g(x)=x^2-_ff_2g for degree 2
28
// and in degree 3, g(x)=x^3-_ff_3g if p=1mod3 else g(x)=x^3-x-_ff_3g
29
30
extern int _ff2_cbrt_setup;
31
extern ff_t _ff2_cbrt_unity[2];
32
33
void ff_ext_setup(void);
34
35
// for convenience
36
static inline void ff2_random(ff_t o[2]) { _ff_random(o[0]); _ff_random(o[1]); }
37
static inline void ff3_random(ff_t o[3]) { _ff_random(o[0]); _ff_random(o[1]); _ff_random(o[2]); }
38
static inline void ff2_set_zero(ff_t o[2]) { _ff_set_zero(o[0]); _ff_set_zero(o[1]); }
39
static inline void ff3_set_zero(ff_t o[3]) { _ff_set_zero(o[0]); _ff_set_zero(o[1]); _ff_set_zero(o[2]); }
40
static inline void ff2_set_one(ff_t o[2]) { _ff_set_one(o[0]); _ff_set_zero(o[1]); }
41
static inline void ff3_set_one(ff_t o[3]) { _ff_set_one(o[0]); _ff_set_zero(o[1]); _ff_set_zero(o[2]); }
42
static inline int ff2_zero(ff_t o[3]) { return ( _ff_zero(o[0]) && _ff_zero(o[1]) ); }
43
static inline int ff3_zero(ff_t o[3]) { return ( _ff_zero(o[0]) && _ff_zero(o[1]) && _ff_zero(o[2]) ); }
44
static inline int ff2_one(ff_t o[3]) { return ( _ff_one(o[0]) && _ff_zero(o[1]) ); }
45
static inline int ff3_one(ff_t o[3]) { return ( _ff_one(o[0]) && _ff_zero(o[1]) && _ff_zero(o[2]) ); }
46
static inline int ff2_set(ff_t o[3], ff_t a[3]) { _ff_set(o[0],a[0]); _ff_set(o[1],a[1]); }
47
static inline int ff3_set(ff_t o[3], ff_t a[3]) { _ff_set(o[0],a[0]); _ff_set(o[1],a[1]); _ff_set(o[2],a[2]); }
48
static inline int ff2_equal(ff_t o[3], ff_t a[3]) { return (_ff_equal(a[0],o[0])&&_ff_equal(a[1],o[1])); }
49
static inline int ff3_equal(ff_t o[3], ff_t a[3]) { return (_ff_equal(a[0],o[0])&&_ff_equal(a[1],o[1])&&_ff_equal(a[2],o[2])); }
50
51
// overlap ok
52
static inline void ff2_add(ff_t o[2], ff_t a[2], ff_t b[2]) { _ff_add(o[0],a[0],b[0]); _ff_add(o[1],a[1],b[1]); }
53
static inline void ff3_add(ff_t o[3], ff_t a[3], ff_t b[3]) { _ff_add(o[0],a[0],b[0]); _ff_add(o[1],a[1],b[1]); _ff_add(o[2],a[2],b[2]); }
54
static inline void ff2_sub(ff_t o[2], ff_t a[2], ff_t b[2]) { _ff_sub(o[0],a[0],b[0]); _ff_sub(o[1],a[1],b[1]); }
55
static inline void ff3_sub(ff_t o[3], ff_t a[3], ff_t b[3]) { _ff_sub(o[0],a[0],b[0]); _ff_sub(o[1],a[1],b[1]); _ff_sub(o[2],a[2],b[2]); }
56
static inline void ff2_neg(ff_t o[2], ff_t a[2]) { _ff_neg(o[0],a[0]); _ff_neg(o[1],a[1]); }
57
static inline void ff3_neg(ff_t o[3], ff_t a[3]) { _ff_neg(o[0],a[0]); _ff_neg(o[1],a[1]); _ff_neg(o[2],a[2]); }
58
static inline void ff2_negate(ff_t a[2]) { ff_negate(a[0]); ff_negate(a[1]); }
59
static inline void ff3_negate(ff_t a[3]) { ff_negate(a[0]); ff_negate(a[1]); ff_negate(a[2]); }
60
61
#define ff2_norm(o,a) ff2_norm_s(o,a,_ff_2g)
62
static inline void ff2_norm_s (ff_t o[1], ff_t a[2], ff_t s)
63
{
64
register ff_t t1,t2;
65
66
_ff_square(t1,a[1]);
67
ff_square(o[0],a[0]);
68
_ff_mult(t2,t1,s);
69
_ff_subfrom(o[0],t2);
70
// 3M+1A
71
}
72
73
#define ff2_trace(o,a) ff_add(*(o),*(a),*(a))
74
75
static inline void ff2_scalar_mult (ff_t o[3], ff_t c, ff_t a[3]) { ff_mult(o[0],c,a[0]); ff_mult(o[1],c,a[1]); }
76
77
#define ff2_mult(o,a,b) ff2_mult_s(o,a,b,_ff_2g)
78
static inline void ff2_mult_s (ff_t o[2], ff_t a[2], ff_t b[2], ff_t s)
79
{
80
register ff_t t0, t1, t2;
81
82
_ff_add(t0,a[0],a[1]); _ff_add(t1,b[0],b[1]); _ff_mult(t2,t0,t1);
83
_ff_mult(t0, a[0], b[0]); _ff_mult(t1, a[1], b[1]);
84
_ff_subfrom(t2,t0);
85
_ff_sub(o[1],t2,t1);
86
_ff_mult(t2,t1,s);
87
_ff_add(o[0],t0,t2);
88
// 4M+5A could use 5M+2A (essentially the same speed)
89
}
90
91
// multiplies (b[1]z+b[0])*(z+a) mod (z^2-s)
92
static inline void ff2_mult_zpa_s (ff_t o[2], ff_t b[2], ff_t a, ff_t s)
93
{
94
register ff_t t0,t1,t2;
95
96
_ff_mult(t1,a,b[1]); _ff_mult(t0,a,b[0]); _ff_mult(t2,b[1],s);
97
_ff_add(o[1],b[0],t1); _ff_add(o[0],t0,t2);
98
/// 3M+2A
99
}
100
101
#define ff2_square(o,a) ff2_square_s(o,a,_ff_2g)
102
static inline void ff2_square_s (ff_t o[2], ff_t a[2], ff_t s)
103
{
104
register ff_t t0, t1, t2;
105
106
_ff_square(t0, a[0]); _ff_square(t1, a[1]);
107
_ff_mult(t2,a[0],a[1]);
108
_ff_add(o[1],t2,t2);
109
_ff_mult(t2,t1,s);
110
_ff_add(o[0],t0,t2);
111
// 4M+2A
112
}
113
114
#define ff2_exp_ui(o,a,e) ff2_exp_ui_s(o,a,e,_ff_2g)
115
void ff2_exp_ui_s (ff_t o[2], ff_t a[2], unsigned long e, ff_t s); // computes in F_p[z]/(z^2-s)
116
117
// Cube roots in F_p^2 are only relevant when p=2mod3, since otherwise the 3-Sylow of F_p^2 is the 3-Sylow of F_p.
118
void _ff2_setup_cbrt(void);
119
static inline void ff2_setup_cbrt(void) { if ( ! _ff2_cbrt_setup ) _ff2_setup_cbrt(); }
120
int ff2_3Sylow_invcbrt (ff_t o[2], ff_t a[2]);
121
122
// Note ff3_setup_ncr() must be called before using any of the ff3 functions below
123
// ff3_poly_eval, ff3_sqrt, and ff3_exp_ui do this automatically
124
125
static inline void ff3_scalar_mult (ff_t o[3], ff_t c, ff_t a[3]) { ff_mult(o[0],c,a[0]); ff_mult(o[1],c,a[1]); ff_mult(o[2],c,a[2]); }
126
void ff3_mult (ff_t o[3], ff_t a[3], ff_t b[3]); // too long to bother inlining
127
void ff3_square (ff_t o[3], ff_t a[3]);
128
129
// exponentiating by p (the Frobenius map) is very fast, potentially only 2M and at most 6M+4A, faster than ff3_mult by a lot
130
void ff3_exp_p (ff_t o[3], ff_t a[3]);
131
132
extern int _ff3_trace_z2;
133
134
// tr(a[0]+a[1]z+a[2]z^2 = 3a[0]+a[1]tr(z)+a[2]tr(z^2) = 3a[0]+a[2]tr(z^2) since tr(z)=0 for z^3-z-s=0 and z^3-s=0
135
static inline void ff3_trace (ff_t o[1], ff_t a[3])
136
{
137
register ff_t t1,t2;
138
139
_ff_add(t1,a[0],a[0]);
140
_ff_add(o[0],t1,a[0]);
141
if ( ! _ff3_trace_z2 ) return;
142
_ff_add(t2,a[2],a[2]); // we rely on the fact that tr(z^2) is either 0 or 2
143
_ff_addto(o[0],t2);
144
}
145
146
// norm(a)=a*a^p*a^(p^2), uses 16M+17A or 27M+23A, about 2 or 3 ff3_mults.
147
static inline void ff3_norm (ff_t o[1], ff_t a[3])
148
{
149
ff_t x[3],y[3];
150
register ff_t t1, t2;
151
152
ff3_exp_p (x,a); // x=a^p
153
ff3_exp_p (y,x); // y=a^(p^2)
154
ff3_mult(x,x,y); // x=a^(p^2+p)
155
// we know the norm is in F_p, so we only compute the constant coefficient of a*x
156
_ff_mult(t1,a[2],x[1]); // t1=a2x1
157
_ff_mult(t2,a[1],x[2]); // t2=a1x2
158
_ff_addto(t1,t2); // t1=a2x1+a1x2
159
_ff_mult(t2,t1,_ff_3g); // t2=(a2x1+a1x2)s
160
_ff_mult(t1,a[0],x[0]); // t1=a0x0
161
_ff_add(o[0],t1,t2); // o=a0x0+(a2x2+a1x2)s note that this works for both p=1mod3 or p=2mod3
162
}
163
164
void ff2_poly_eval (ff_t y[2], ff_t f[], int d, ff_t x[2]);
165
void ff3_poly_eval (ff_t y[3], ff_t f[], int d, ff_t x[3]);
166
167
int ff2_sqrt(ff_t o[2], ff_t a[2]);
168
int ff3_sqrt (ff_t o[3], ff_t a[3]);
169
170
int ff3_trsqrt_zpa_mod_rs (ff_t o[1], ff_t a, ff_t r, ff_t s); // Computes tr(sqrt(z)) in F_p^3=F_p[z]/(z^3-rz-s). This is a support function for factoring quartics.
171
172
void ff3_exp_ui (ff_t o[3], ff_t a[3], unsigned long e);
173
void ff3_exp_ui_rs (ff_t o[3], ff_t a[3], unsigned long e, ff_t r, ff_t s);
174
// inversion not currently supported/needed in degree 3
175
176
void ff3_zn_mod (ff_t o[3], unsigned long n, ff_t f[4]); // only looks at f[0] and f[1], assumes f[2]=0 and f[3]=1
177
178
179
#endif
180
181