1 // F_p for small p, i.e. at most sizeof(long) bytes long.
2 // Assumes long long is at least twice long.
3 
4 // TODO: Fix outstanding bugs and use in PBC.
5 
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdint.h> // for intptr_t
9 #include <stdlib.h>
10 #include <string.h>
11 #include <gmp.h>
12 #include "pbc_utils.h"
13 #include "pbc_field.h"
14 #include "pbc_random.h"
15 #include "pbc_fp.h"
16 #include "pbc_memory.h"
17 
18 // Mostly wrappers. We use GMP routines for pow_mpz and invert.
19 
fp_init(element_ptr e)20 static void fp_init(element_ptr e) {
21   unsigned long *p = e->data = pbc_malloc(sizeof(unsigned long));
22   *p = 0;
23 }
24 
fp_clear(element_ptr e)25 static void fp_clear(element_ptr e) {
26   pbc_free(e->data);
27 }
28 
fp_set_mpz(element_ptr e,mpz_ptr z)29 static void fp_set_mpz(element_ptr e, mpz_ptr z) {
30   mpz_t r;
31   mpz_init(r);
32   unsigned long *p = e->field->data;
33   unsigned long *l = e->data;
34   mpz_fdiv_r_ui(r, z, *p);
35   *l = mpz_get_ui(r);
36   mpz_clear(r);
37 }
38 
fp_set_si(element_ptr e,signed long int op)39 static void fp_set_si(element_ptr e, signed long int op) {
40   unsigned long int *d = e->data;
41   unsigned long *p = e->field->data;
42   if (op < 0) {
43     *d = (-op) % *p;
44     *d = *p - *d;
45   } else {
46     *d = op % *p;
47   }
48 }
49 
fp_to_mpz(mpz_ptr z,element_ptr e)50 static void fp_to_mpz(mpz_ptr z, element_ptr e) {
51   unsigned long int *l = e->data;
52   mpz_set_ui(z, *l);
53 }
54 
fp_set0(element_ptr e)55 static void fp_set0(element_ptr e) {
56   unsigned long int *l = e->data;
57   *l = 0;
58 }
59 
fp_set1(element_ptr e)60 static void fp_set1(element_ptr e) {
61   unsigned long int *l = e->data;
62   *l = 1;
63 }
64 
fp_is1(element_ptr e)65 static int fp_is1(element_ptr e) {
66   unsigned long int *l = e->data;
67   return *l == 1;
68 }
69 
fp_is0(element_ptr e)70 static int fp_is0(element_ptr e) {
71   unsigned long int *l = e->data;
72   return *l == 0;
73 }
74 
fp_out_str(FILE * stream,int base,element_ptr e)75 static size_t fp_out_str(FILE *stream, int base, element_ptr e) {
76   size_t result;
77   mpz_t z;
78   mpz_init(z);
79   fp_to_mpz(z, e);
80   result = mpz_out_str(stream, base, z);
81   mpz_clear(z);
82   return result;
83 }
84 
fp_add(element_ptr c,element_ptr a,element_ptr b)85 static void fp_add(element_ptr c, element_ptr a, element_ptr b) {
86   unsigned long *prime = a->field->data;
87   unsigned long *p = a->data;
88   unsigned long *q = b->data;
89   unsigned long *r = c->data;
90   unsigned long l0;
91   l0 = *p + *q;
92   if (l0 < *p) {
93     //overflow
94     l0 -= *prime;
95   }
96   *r = l0 % *prime;
97 }
98 
fp_double(element_ptr c,element_ptr a)99 static void fp_double(element_ptr c, element_ptr a) {
100   unsigned long *prime = a->field->data;
101   unsigned long *p = a->data;
102   unsigned long *r = c->data;
103   *r = 2 * *p;
104   if (*r < *p) {
105     //overflow
106     *r -= *prime;
107   }
108   *r = *r % *prime;
109 }
110 
fp_sub(element_ptr c,element_ptr a,element_ptr b)111 static void fp_sub(element_ptr c, element_ptr a, element_ptr b) {
112   unsigned long *prime = a->field->data;
113   unsigned long *p = a->data;
114   unsigned long *q = b->data;
115   unsigned long *r = c->data;
116 
117   if (*p >= *q) {
118     *r = *p - *q;
119   } else {
120     *r = *prime - *q + *p;
121   }
122 }
123 
fp_mul(element_ptr c,element_ptr a,element_ptr b)124 static void fp_mul(element_ptr c, element_ptr a, element_ptr b) {
125   unsigned long *prime = a->field->data;
126   unsigned long *p = a->data;
127   unsigned long *q = b->data;
128   unsigned long long ll;
129   unsigned long *r = c->data;
130 
131   ll = *p * *q;
132   *r = ll % *prime;
133 }
134 
fp_square(element_ptr c,element_ptr a)135 static void fp_square(element_ptr c, element_ptr a) {
136   fp_mul(c, a, a);
137 }
138 
fp_neg(element_ptr c,element_ptr a)139 static void fp_neg(element_ptr c, element_ptr a) {
140   unsigned long *prime = a->field->data;
141   unsigned long *r = c->data;
142   unsigned long *p = a->data;
143   if (*p) {
144     *r = *prime - *p;
145   } else {
146     *r = 0;
147   }
148 }
149 
fp_mul_si(element_ptr c,element_ptr a,signed long int op)150 static void fp_mul_si(element_ptr c, element_ptr a, signed long int op) {
151   unsigned long *prime = a->field->data;
152   unsigned long *p = a->data;
153   unsigned long long ll;
154   unsigned long *r = c->data;
155 
156   ll = *p * op;
157   *r = ll % *prime;
158 }
159 
fp_pow_mpz(element_ptr c,element_ptr a,mpz_ptr op)160 static void fp_pow_mpz(element_ptr c, element_ptr a, mpz_ptr op) {
161   unsigned long *r = c->data;
162   mpz_t z;
163   mpz_init(z);
164   fp_to_mpz(z, a);
165   mpz_powm(z, z, op, a->field->order);
166   *r = mpz_get_ui(z);
167   mpz_clear(z);
168 }
169 
fp_set(element_ptr c,element_ptr a)170 static void fp_set(element_ptr c, element_ptr a) {
171   unsigned long *p = a->data;
172   unsigned long *r = c->data;
173   *r = *p;
174 }
175 
fp_invert(element_ptr c,element_ptr a)176 static void fp_invert(element_ptr c, element_ptr a) {
177   unsigned long *r = c->data;
178   mpz_t z;
179   mpz_init(z);
180   fp_to_mpz(z, a);
181   mpz_invert(z, z, a->field->order);
182   *r = mpz_get_ui(z);
183   mpz_clear(z);
184 }
185 
fp_random(element_ptr c)186 static void fp_random(element_ptr c) {
187   unsigned long *r = c->data;
188   mpz_t z;
189   mpz_init(z);
190   pbc_mpz_random(z, c->field->order);
191   *r = mpz_get_ui(z);
192   mpz_clear(z);
193 }
194 
fp_from_hash(element_ptr n,void * data,int len)195 static void fp_from_hash(element_ptr n, void *data, int len) {
196   mpz_t z;
197 
198   mpz_init(z);
199   mpz_import(z, len, -1, 1, -1, 0, data);
200   fp_set_mpz(n, z);
201   mpz_clear(z);
202 }
203 
fp_cmp(element_ptr a,element_ptr b)204 static int fp_cmp(element_ptr a, element_ptr b) {
205   unsigned long *p = a->data;
206   unsigned long *q = b->data;
207   return *p != *q;
208 }
209 
fp_sgn_odd(element_ptr a)210 static int fp_sgn_odd(element_ptr a) {
211   unsigned long *p = a->data;
212   if (!*p) return 0;
213   return *p & 1 ? 1 : -1;
214 }
215 
fp_is_sqr(element_ptr a)216 static int fp_is_sqr(element_ptr a) {
217   int res;
218   mpz_t z;
219   mpz_init(z);
220   //0 is a square
221   if (fp_is0(a)) return 1;
222   fp_to_mpz(z, a);
223   res = mpz_legendre(z, a->field->order) == 1;
224   mpz_clear(z);
225   return res;
226 }
227 
fp_to_bytes(unsigned char * data,element_t e)228 static int fp_to_bytes(unsigned char *data, element_t e) {
229   unsigned long *p = e->data;
230   unsigned long l = *p;
231   int i, n = e->field->fixed_length_in_bytes;
232   for (i = 0; i < n; i++) {
233     data[n - i - 1] = (unsigned char) l;
234     l >>= 8;
235   }
236   return n;
237 }
238 
fp_from_bytes(element_t e,unsigned char * data)239 static int fp_from_bytes(element_t e, unsigned char *data) {
240   unsigned char *ptr = data;
241   unsigned long *p = e->data;
242   int i, n = e->field->fixed_length_in_bytes;
243   *p = 0;
244   for (i=0; i<n; i++) {
245     *p <<= 8;
246     *p += *ptr;
247     ptr++;
248   }
249   return n;
250 }
251 
fp_field_clear(field_t f)252 static void fp_field_clear(field_t f) {
253   pbc_free(f->data);
254 }
255 
field_init_tiny_fp(field_ptr f,mpz_t prime)256 void field_init_tiny_fp(field_ptr f, mpz_t prime) {
257   unsigned long *p;
258 
259   PBC_ASSERT(mpz_fits_ulong_p(prime), "modulus too big");
260 
261   field_init(f);
262   f->init = fp_init;
263   f->clear = fp_clear;
264   f->set_si = fp_set_si;
265   f->set_mpz = fp_set_mpz;
266   f->out_str = fp_out_str;
267   f->add = fp_add;
268   f->sub = fp_sub;
269   f->set = fp_set;
270   f->mul = fp_mul;
271   f->mul_si = fp_mul_si;
272   f->square = fp_square;
273   f->doub = fp_double;
274   f->pow_mpz = fp_pow_mpz;
275   f->neg = fp_neg;
276   f->cmp = fp_cmp;
277   f->sign = fp_sgn_odd;
278   f->invert = fp_invert;
279   f->random = fp_random;
280   f->from_hash = fp_from_hash;
281   f->is1 = fp_is1;
282   f->is0 = fp_is0;
283   f->set0 = fp_set0;
284   f->set1 = fp_set1;
285   f->is_sqr = fp_is_sqr;
286   f->sqrt = element_tonelli;
287   f->field_clear = fp_field_clear;
288   f->to_bytes = fp_to_bytes;
289   f->from_bytes = fp_from_bytes;
290   f->to_mpz = fp_to_mpz;
291 
292   p = f->data = pbc_malloc(sizeof(long));
293   *p = mpz_get_ui(prime);
294   {
295     unsigned long int l = 255;
296     f->fixed_length_in_bytes = 1;
297     while (l < *p) {
298       f->fixed_length_in_bytes++;
299       l <<= 8;
300       l += 255;
301     }
302   }
303   mpz_set(f->order, prime);
304 }
305