1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans * Copyright (C) 2017 - This file is part of libecc project
3*f0865ec9SKyle Evans *
4*f0865ec9SKyle Evans * Authors:
5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8*f0865ec9SKyle Evans *
9*f0865ec9SKyle Evans * Contributors:
10*f0865ec9SKyle Evans * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11*f0865ec9SKyle Evans * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12*f0865ec9SKyle Evans *
13*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license.
14*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project.
15*f0865ec9SKyle Evans */
16*f0865ec9SKyle Evans #include <libecc/fp/fp_sqrt.h>
17*f0865ec9SKyle Evans #include <libecc/nn/nn_add.h>
18*f0865ec9SKyle Evans #include <libecc/nn/nn_logical.h>
19*f0865ec9SKyle Evans
20*f0865ec9SKyle Evans /*
21*f0865ec9SKyle Evans * Compute the legendre symbol of an element of Fp:
22*f0865ec9SKyle Evans *
23*f0865ec9SKyle Evans * Legendre(a) = a^((p-1)/2) (p) = { -1, 0, 1 }
24*f0865ec9SKyle Evans *
25*f0865ec9SKyle Evans */
legendre(fp_src_t a)26*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int legendre(fp_src_t a)
27*f0865ec9SKyle Evans {
28*f0865ec9SKyle Evans int ret, iszero, cmp;
29*f0865ec9SKyle Evans fp pow; /* The result if the exponentiation is in Fp */
30*f0865ec9SKyle Evans fp one; /* The element 1 in the field */
31*f0865ec9SKyle Evans nn exp; /* The power exponent is in NN */
32*f0865ec9SKyle Evans pow.magic = one.magic = WORD(0);
33*f0865ec9SKyle Evans exp.magic = WORD(0);
34*f0865ec9SKyle Evans
35*f0865ec9SKyle Evans /* Initialize elements */
36*f0865ec9SKyle Evans ret = fp_check_initialized(a); EG(ret, err);
37*f0865ec9SKyle Evans ret = fp_init(&pow, a->ctx); EG(ret, err);
38*f0865ec9SKyle Evans ret = fp_init(&one, a->ctx); EG(ret, err);
39*f0865ec9SKyle Evans ret = nn_init(&exp, 0); EG(ret, err);
40*f0865ec9SKyle Evans
41*f0865ec9SKyle Evans /* Initialize our variables from the Fp context of the
42*f0865ec9SKyle Evans * input a.
43*f0865ec9SKyle Evans */
44*f0865ec9SKyle Evans ret = fp_init(&pow, a->ctx); EG(ret, err);
45*f0865ec9SKyle Evans ret = fp_init(&one, a->ctx); EG(ret, err);
46*f0865ec9SKyle Evans ret = nn_init(&exp, 0); EG(ret, err);
47*f0865ec9SKyle Evans
48*f0865ec9SKyle Evans /* one = 1 in Fp */
49*f0865ec9SKyle Evans ret = fp_one(&one); EG(ret, err);
50*f0865ec9SKyle Evans
51*f0865ec9SKyle Evans /* Compute the exponent (p-1)/2
52*f0865ec9SKyle Evans * The computation is done in NN, and the division by 2
53*f0865ec9SKyle Evans * is performed using a right shift by one
54*f0865ec9SKyle Evans */
55*f0865ec9SKyle Evans ret = nn_dec(&exp, &(a->ctx->p)); EG(ret, err);
56*f0865ec9SKyle Evans ret = nn_rshift(&exp, &exp, 1); EG(ret, err);
57*f0865ec9SKyle Evans
58*f0865ec9SKyle Evans /* Compute a^((p-1)/2) in Fp using our fp_pow
59*f0865ec9SKyle Evans * API.
60*f0865ec9SKyle Evans */
61*f0865ec9SKyle Evans ret = fp_pow(&pow, a, &exp); EG(ret, err);
62*f0865ec9SKyle Evans
63*f0865ec9SKyle Evans ret = fp_iszero(&pow, &iszero); EG(ret, err);
64*f0865ec9SKyle Evans ret = fp_cmp(&pow, &one, &cmp); EG(ret, err);
65*f0865ec9SKyle Evans if (iszero) {
66*f0865ec9SKyle Evans ret = 0;
67*f0865ec9SKyle Evans } else if (cmp == 0) {
68*f0865ec9SKyle Evans ret = 1;
69*f0865ec9SKyle Evans } else {
70*f0865ec9SKyle Evans ret = -1;
71*f0865ec9SKyle Evans }
72*f0865ec9SKyle Evans
73*f0865ec9SKyle Evans err:
74*f0865ec9SKyle Evans /* Cleaning */
75*f0865ec9SKyle Evans fp_uninit(&pow);
76*f0865ec9SKyle Evans fp_uninit(&one);
77*f0865ec9SKyle Evans nn_uninit(&exp);
78*f0865ec9SKyle Evans
79*f0865ec9SKyle Evans return ret;
80*f0865ec9SKyle Evans }
81*f0865ec9SKyle Evans
82*f0865ec9SKyle Evans /*
83*f0865ec9SKyle Evans * We implement the Tonelli-Shanks algorithm for finding
84*f0865ec9SKyle Evans * square roots (quadratic residues) modulo a prime number,
85*f0865ec9SKyle Evans * i.e. solving the equation:
86*f0865ec9SKyle Evans * x^2 = n (p)
87*f0865ec9SKyle Evans * where p is a prime number. This can be seen as an equation
88*f0865ec9SKyle Evans * over the finite field Fp where a and x are elements of
89*f0865ec9SKyle Evans * this finite field.
90*f0865ec9SKyle Evans * Source: https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
91*f0865ec9SKyle Evans * All ≡ are taken to mean (mod p) unless stated otherwise.
92*f0865ec9SKyle Evans * Input : p an odd prime, and an integer n .
93*f0865ec9SKyle Evans * Step 0. Check that n is indeed a square : (n | p) must be ≡ 1
94*f0865ec9SKyle Evans * Step 1. [Factors out powers of 2 from p-1] Define q -odd- and s such as p-1 = q * 2^s
95*f0865ec9SKyle Evans * - if s = 1 , i.e p ≡ 3 (mod 4) , output the two solutions r ≡ +/- n^((p+1)/4) .
96*f0865ec9SKyle Evans * Step 2. Select a non-square z such as (z | p) = -1 , and set c ≡ z^q .
97*f0865ec9SKyle Evans * Step 3. Set r ≡ n ^((q+1)/2) , t ≡ n^q, m = s .
98*f0865ec9SKyle Evans * Step 4. Loop.
99*f0865ec9SKyle Evans * - if t ≡ 1 output r, p-r .
100*f0865ec9SKyle Evans * - Otherwise find, by repeated squaring, the lowest i , 0 < i < m , such as t^(2^i) ≡ 1
101*f0865ec9SKyle Evans * - Let b ≡ c^(2^(m-i-1)), and set r ≡ r*b, t ≡ t*b^2 , c ≡ b^2 and m = i.
102*f0865ec9SKyle Evans *
103*f0865ec9SKyle Evans * NOTE: the algorithm is NOT constant time.
104*f0865ec9SKyle Evans *
105*f0865ec9SKyle Evans * The outputs, sqrt1 and sqrt2 ARE initialized by the function.
106*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error (in which case values of sqrt1 and sqrt2
107*f0865ec9SKyle Evans * must not be considered).
108*f0865ec9SKyle Evans *
109*f0865ec9SKyle Evans * Aliasing is supported.
110*f0865ec9SKyle Evans *
111*f0865ec9SKyle Evans */
fp_sqrt(fp_t sqrt1,fp_t sqrt2,fp_src_t n)112*f0865ec9SKyle Evans int fp_sqrt(fp_t sqrt1, fp_t sqrt2, fp_src_t n)
113*f0865ec9SKyle Evans {
114*f0865ec9SKyle Evans int ret, iszero, cmp, isodd;
115*f0865ec9SKyle Evans nn q, s, one_nn, two_nn, m, i, tmp_nn;
116*f0865ec9SKyle Evans fp z, t, b, r, c, one_fp, tmp_fp, __n;
117*f0865ec9SKyle Evans fp_t _n = &__n;
118*f0865ec9SKyle Evans q.magic = s.magic = one_nn.magic = two_nn.magic = m.magic = WORD(0);
119*f0865ec9SKyle Evans i.magic = tmp_nn.magic = z.magic = t.magic = b.magic = WORD(0);
120*f0865ec9SKyle Evans r.magic = c.magic = one_fp.magic = tmp_fp.magic = __n.magic = WORD(0);
121*f0865ec9SKyle Evans
122*f0865ec9SKyle Evans ret = nn_init(&q, 0); EG(ret, err);
123*f0865ec9SKyle Evans ret = nn_init(&s, 0); EG(ret, err);
124*f0865ec9SKyle Evans ret = nn_init(&tmp_nn, 0); EG(ret, err);
125*f0865ec9SKyle Evans ret = nn_init(&one_nn, 0); EG(ret, err);
126*f0865ec9SKyle Evans ret = nn_init(&two_nn, 0); EG(ret, err);
127*f0865ec9SKyle Evans ret = nn_init(&m, 0); EG(ret, err);
128*f0865ec9SKyle Evans ret = nn_init(&i, 0); EG(ret, err);
129*f0865ec9SKyle Evans ret = fp_init(&z, n->ctx); EG(ret, err);
130*f0865ec9SKyle Evans ret = fp_init(&t, n->ctx); EG(ret, err);
131*f0865ec9SKyle Evans ret = fp_init(&b, n->ctx); EG(ret, err);
132*f0865ec9SKyle Evans ret = fp_init(&r, n->ctx); EG(ret, err);
133*f0865ec9SKyle Evans ret = fp_init(&c, n->ctx); EG(ret, err);
134*f0865ec9SKyle Evans ret = fp_init(&one_fp, n->ctx); EG(ret, err);
135*f0865ec9SKyle Evans ret = fp_init(&tmp_fp, n->ctx); EG(ret, err);
136*f0865ec9SKyle Evans
137*f0865ec9SKyle Evans /* Handle input aliasing */
138*f0865ec9SKyle Evans ret = fp_copy(_n, n); EG(ret, err);
139*f0865ec9SKyle Evans
140*f0865ec9SKyle Evans /* Initialize outputs */
141*f0865ec9SKyle Evans ret = fp_init(sqrt1, _n->ctx); EG(ret, err);
142*f0865ec9SKyle Evans ret = fp_init(sqrt2, _n->ctx); EG(ret, err);
143*f0865ec9SKyle Evans
144*f0865ec9SKyle Evans /* one_nn = 1 in NN */
145*f0865ec9SKyle Evans ret = nn_one(&one_nn); EG(ret, err);
146*f0865ec9SKyle Evans /* two_nn = 2 in NN */
147*f0865ec9SKyle Evans ret = nn_set_word_value(&two_nn, WORD(2)); EG(ret, err);
148*f0865ec9SKyle Evans
149*f0865ec9SKyle Evans /* If our p prime of Fp is 2, then return the input as square roots */
150*f0865ec9SKyle Evans ret = nn_cmp(&(_n->ctx->p), &two_nn, &cmp); EG(ret, err);
151*f0865ec9SKyle Evans if (cmp == 0) {
152*f0865ec9SKyle Evans ret = fp_copy(sqrt1, _n); EG(ret, err);
153*f0865ec9SKyle Evans ret = fp_copy(sqrt2, _n); EG(ret, err);
154*f0865ec9SKyle Evans ret = 0;
155*f0865ec9SKyle Evans goto err;
156*f0865ec9SKyle Evans }
157*f0865ec9SKyle Evans
158*f0865ec9SKyle Evans /* Square root of 0 is 0 */
159*f0865ec9SKyle Evans ret = fp_iszero(_n, &iszero); EG(ret, err);
160*f0865ec9SKyle Evans if (iszero) {
161*f0865ec9SKyle Evans ret = fp_zero(sqrt1); EG(ret, err);
162*f0865ec9SKyle Evans ret = fp_zero(sqrt2); EG(ret, err);
163*f0865ec9SKyle Evans ret = 0;
164*f0865ec9SKyle Evans goto err;
165*f0865ec9SKyle Evans }
166*f0865ec9SKyle Evans /* Step 0. Check that n is indeed a square : (n | p) must be ≡ 1 */
167*f0865ec9SKyle Evans if (legendre(_n) != 1) {
168*f0865ec9SKyle Evans /* a is not a square */
169*f0865ec9SKyle Evans ret = -1;
170*f0865ec9SKyle Evans goto err;
171*f0865ec9SKyle Evans }
172*f0865ec9SKyle Evans /* Step 1. [Factors out powers of 2 from p-1] Define q -odd- and s such as p-1 = q * 2^s */
173*f0865ec9SKyle Evans /* s = 0 */
174*f0865ec9SKyle Evans ret = nn_zero(&s); EG(ret, err);
175*f0865ec9SKyle Evans /* q = p - 1 */
176*f0865ec9SKyle Evans ret = nn_copy(&q, &(_n->ctx->p)); EG(ret, err);
177*f0865ec9SKyle Evans ret = nn_dec(&q, &q); EG(ret, err);
178*f0865ec9SKyle Evans while (1) {
179*f0865ec9SKyle Evans /* i is used as a temporary unused variable here */
180*f0865ec9SKyle Evans ret = nn_divrem(&tmp_nn, &i, &q, &two_nn); EG(ret, err);
181*f0865ec9SKyle Evans ret = nn_inc(&s, &s); EG(ret, err);
182*f0865ec9SKyle Evans ret = nn_copy(&q, &tmp_nn); EG(ret, err);
183*f0865ec9SKyle Evans /* If r is odd, we have finished our division */
184*f0865ec9SKyle Evans ret = nn_isodd(&q, &isodd); EG(ret, err);
185*f0865ec9SKyle Evans if (isodd) {
186*f0865ec9SKyle Evans break;
187*f0865ec9SKyle Evans }
188*f0865ec9SKyle Evans }
189*f0865ec9SKyle Evans /* - if s = 1 , i.e p ≡ 3 (mod 4) , output the two solutions r ≡ +/- n^((p+1)/4) . */
190*f0865ec9SKyle Evans ret = nn_cmp(&s, &one_nn, &cmp); EG(ret, err);
191*f0865ec9SKyle Evans if (cmp == 0) {
192*f0865ec9SKyle Evans ret = nn_inc(&tmp_nn, &(_n->ctx->p)); EG(ret, err);
193*f0865ec9SKyle Evans ret = nn_rshift(&tmp_nn, &tmp_nn, 2); EG(ret, err);
194*f0865ec9SKyle Evans ret = fp_pow(sqrt1, _n, &tmp_nn); EG(ret, err);
195*f0865ec9SKyle Evans ret = fp_neg(sqrt2, sqrt1); EG(ret, err);
196*f0865ec9SKyle Evans ret = 0;
197*f0865ec9SKyle Evans goto err;
198*f0865ec9SKyle Evans }
199*f0865ec9SKyle Evans /* Step 2. Select a non-square z such as (z | p) = -1 , and set c ≡ z^q . */
200*f0865ec9SKyle Evans ret = fp_zero(&z); EG(ret, err);
201*f0865ec9SKyle Evans while (legendre(&z) != -1) {
202*f0865ec9SKyle Evans ret = fp_inc(&z, &z); EG(ret, err);
203*f0865ec9SKyle Evans }
204*f0865ec9SKyle Evans ret = fp_pow(&c, &z, &q); EG(ret, err);
205*f0865ec9SKyle Evans /* Step 3. Set r ≡ n ^((q+1)/2) , t ≡ n^q, m = s . */
206*f0865ec9SKyle Evans ret = nn_inc(&tmp_nn, &q); EG(ret, err);
207*f0865ec9SKyle Evans ret = nn_rshift(&tmp_nn, &tmp_nn, 1); EG(ret, err);
208*f0865ec9SKyle Evans ret = fp_pow(&r, _n, &tmp_nn); EG(ret, err);
209*f0865ec9SKyle Evans ret = fp_pow(&t, _n, &q); EG(ret, err);
210*f0865ec9SKyle Evans ret = nn_copy(&m, &s); EG(ret, err);
211*f0865ec9SKyle Evans ret = fp_one(&one_fp); EG(ret, err);
212*f0865ec9SKyle Evans
213*f0865ec9SKyle Evans /* Step 4. Loop. */
214*f0865ec9SKyle Evans while (1) {
215*f0865ec9SKyle Evans /* - if t ≡ 1 output r, p-r . */
216*f0865ec9SKyle Evans ret = fp_cmp(&t, &one_fp, &cmp); EG(ret, err);
217*f0865ec9SKyle Evans if (cmp == 0) {
218*f0865ec9SKyle Evans ret = fp_copy(sqrt1, &r); EG(ret, err);
219*f0865ec9SKyle Evans ret = fp_neg(sqrt2, sqrt1); EG(ret, err);
220*f0865ec9SKyle Evans ret = 0;
221*f0865ec9SKyle Evans goto err;
222*f0865ec9SKyle Evans }
223*f0865ec9SKyle Evans /* - Otherwise find, by repeated squaring, the lowest i , 0 < i < m , such as t^(2^i) ≡ 1 */
224*f0865ec9SKyle Evans ret = nn_one(&i); EG(ret, err);
225*f0865ec9SKyle Evans ret = fp_copy(&tmp_fp, &t); EG(ret, err);
226*f0865ec9SKyle Evans while (1) {
227*f0865ec9SKyle Evans ret = fp_sqr(&tmp_fp, &tmp_fp); EG(ret, err);
228*f0865ec9SKyle Evans ret = fp_cmp(&tmp_fp, &one_fp, &cmp); EG(ret, err);
229*f0865ec9SKyle Evans if (cmp == 0) {
230*f0865ec9SKyle Evans break;
231*f0865ec9SKyle Evans }
232*f0865ec9SKyle Evans ret = nn_inc(&i, &i); EG(ret, err);
233*f0865ec9SKyle Evans ret = nn_cmp(&i, &m, &cmp); EG(ret, err);
234*f0865ec9SKyle Evans if (cmp == 0) {
235*f0865ec9SKyle Evans /* i has reached m, that should not happen ... */
236*f0865ec9SKyle Evans ret = -2;
237*f0865ec9SKyle Evans goto err;
238*f0865ec9SKyle Evans }
239*f0865ec9SKyle Evans }
240*f0865ec9SKyle Evans /* - Let b ≡ c^(2^(m-i-1)), and set r ≡ r*b, t ≡ t*b^2 , c ≡ b^2 and m = i. */
241*f0865ec9SKyle Evans ret = nn_sub(&tmp_nn, &m, &i); EG(ret, err);
242*f0865ec9SKyle Evans ret = nn_dec(&tmp_nn, &tmp_nn); EG(ret, err);
243*f0865ec9SKyle Evans ret = fp_copy(&b, &c); EG(ret, err);
244*f0865ec9SKyle Evans ret = nn_iszero(&tmp_nn, &iszero); EG(ret, err);
245*f0865ec9SKyle Evans while (!iszero) {
246*f0865ec9SKyle Evans ret = fp_sqr(&b, &b); EG(ret, err);
247*f0865ec9SKyle Evans ret = nn_dec(&tmp_nn, &tmp_nn); EG(ret, err);
248*f0865ec9SKyle Evans ret = nn_iszero(&tmp_nn, &iszero); EG(ret, err);
249*f0865ec9SKyle Evans }
250*f0865ec9SKyle Evans /* r ≡ r*b */
251*f0865ec9SKyle Evans ret = fp_mul(&r, &r, &b); EG(ret, err);
252*f0865ec9SKyle Evans /* c ≡ b^2 */
253*f0865ec9SKyle Evans ret = fp_sqr(&c, &b); EG(ret, err);
254*f0865ec9SKyle Evans /* t ≡ t*b^2 */
255*f0865ec9SKyle Evans ret = fp_mul(&t, &t, &c); EG(ret, err);
256*f0865ec9SKyle Evans /* m = i */
257*f0865ec9SKyle Evans ret = nn_copy(&m, &i); EG(ret, err);
258*f0865ec9SKyle Evans }
259*f0865ec9SKyle Evans
260*f0865ec9SKyle Evans err:
261*f0865ec9SKyle Evans /* Uninitialize local variables */
262*f0865ec9SKyle Evans nn_uninit(&q);
263*f0865ec9SKyle Evans nn_uninit(&s);
264*f0865ec9SKyle Evans nn_uninit(&tmp_nn);
265*f0865ec9SKyle Evans nn_uninit(&one_nn);
266*f0865ec9SKyle Evans nn_uninit(&two_nn);
267*f0865ec9SKyle Evans nn_uninit(&m);
268*f0865ec9SKyle Evans nn_uninit(&i);
269*f0865ec9SKyle Evans fp_uninit(&z);
270*f0865ec9SKyle Evans fp_uninit(&t);
271*f0865ec9SKyle Evans fp_uninit(&b);
272*f0865ec9SKyle Evans fp_uninit(&r);
273*f0865ec9SKyle Evans fp_uninit(&c);
274*f0865ec9SKyle Evans fp_uninit(&one_fp);
275*f0865ec9SKyle Evans fp_uninit(&tmp_fp);
276*f0865ec9SKyle Evans fp_uninit(&__n);
277*f0865ec9SKyle Evans
278*f0865ec9SKyle Evans PTR_NULLIFY(_n);
279*f0865ec9SKyle Evans
280*f0865ec9SKyle Evans return ret;
281*f0865ec9SKyle Evans }
282