]> Git Repo - secp256k1.git/blob - src/num_gmp_impl.h
Implement endomorphism optimization for secp256k1_ecmult_const
[secp256k1.git] / src / num_gmp_impl.h
1 /**********************************************************************
2  * Copyright (c) 2013, 2014 Pieter Wuille                             *
3  * Distributed under the MIT software license, see the accompanying   *
4  * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5  **********************************************************************/
6
7 #ifndef _SECP256K1_NUM_REPR_IMPL_H_
8 #define _SECP256K1_NUM_REPR_IMPL_H_
9
10 #include <string.h>
11 #include <stdlib.h>
12 #include <gmp.h>
13
14 #include "util.h"
15 #include "num.h"
16
17 #ifdef VERIFY
18 static void secp256k1_num_sanity(const secp256k1_num_t *a) {
19     VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0));
20 }
21 #else
22 #define secp256k1_num_sanity(a) do { } while(0)
23 #endif
24
25 static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
26     *r = *a;
27 }
28
29 static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
30     unsigned char tmp[65];
31     int len = 0;
32     int shift = 0;
33     if (a->limbs>1 || a->data[0] != 0) {
34         len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);
35     }
36     while (shift < len && tmp[shift] == 0) shift++;
37     VERIFY_CHECK(len-shift <= (int)rlen);
38     memset(r, 0, rlen - len + shift);
39     if (len > shift) {
40         memcpy(r + rlen - len + shift, tmp + shift, len - shift);
41     }
42     memset(tmp, 0, sizeof(tmp));
43 }
44
45 static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
46     int len;
47     VERIFY_CHECK(alen > 0);
48     VERIFY_CHECK(alen <= 64);
49     len = mpn_set_str(r->data, a, alen, 256);
50     if (len == 0) {
51         r->data[0] = 0;
52         len = 1;
53     }
54     VERIFY_CHECK(len <= NUM_LIMBS*2);
55     r->limbs = len;
56     r->neg = 0;
57     while (r->limbs > 1 && r->data[r->limbs-1]==0) {
58         r->limbs--;
59     }
60 }
61
62 static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
63     mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
64     r->limbs = a->limbs;
65     if (c != 0) {
66         VERIFY_CHECK(r->limbs < 2*NUM_LIMBS);
67         r->data[r->limbs++] = c;
68     }
69 }
70
71 static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
72     mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
73     VERIFY_CHECK(c == 0);
74     r->limbs = a->limbs;
75     while (r->limbs > 1 && r->data[r->limbs-1]==0) {
76         r->limbs--;
77     }
78 }
79
80 static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
81     secp256k1_num_sanity(r);
82     secp256k1_num_sanity(m);
83
84     if (r->limbs >= m->limbs) {
85         mp_limb_t t[2*NUM_LIMBS];
86         mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs);
87         memset(t, 0, sizeof(t));
88         r->limbs = m->limbs;
89         while (r->limbs > 1 && r->data[r->limbs-1]==0) {
90             r->limbs--;
91         }
92     }
93
94     if (r->neg && (r->limbs > 1 || r->data[0] != 0)) {
95         secp256k1_num_sub_abs(r, m, r);
96         r->neg = 0;
97     }
98 }
99
100 static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
101     int i;
102     mp_limb_t g[NUM_LIMBS+1];
103     mp_limb_t u[NUM_LIMBS+1];
104     mp_limb_t v[NUM_LIMBS+1];
105     mp_size_t sn;
106     mp_size_t gn;
107     secp256k1_num_sanity(a);
108     secp256k1_num_sanity(m);
109
110     /** mpn_gcdext computes: (G,S) = gcdext(U,V), where
111      *  * G = gcd(U,V)
112      *  * G = U*S + V*T
113      *  * U has equal or more limbs than V, and V has no padding
114      *  If we set U to be (a padded version of) a, and V = m:
115      *    G = a*S + m*T
116      *    G = a*S mod m
117      *  Assuming G=1:
118      *    S = 1/a mod m
119      */
120     VERIFY_CHECK(m->limbs <= NUM_LIMBS);
121     VERIFY_CHECK(m->data[m->limbs-1] != 0);
122     for (i = 0; i < m->limbs; i++) {
123         u[i] = (i < a->limbs) ? a->data[i] : 0;
124         v[i] = m->data[i];
125     }
126     sn = NUM_LIMBS+1;
127     gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
128     VERIFY_CHECK(gn == 1);
129     VERIFY_CHECK(g[0] == 1);
130     r->neg = a->neg ^ m->neg;
131     if (sn < 0) {
132         mpn_sub(r->data, m->data, m->limbs, r->data, -sn);
133         r->limbs = m->limbs;
134         while (r->limbs > 1 && r->data[r->limbs-1]==0) {
135             r->limbs--;
136         }
137     } else {
138         r->limbs = sn;
139     }
140     memset(g, 0, sizeof(g));
141     memset(u, 0, sizeof(u));
142     memset(v, 0, sizeof(v));
143 }
144
145 static int secp256k1_num_is_zero(const secp256k1_num_t *a) {
146     return (a->limbs == 1 && a->data[0] == 0);
147 }
148
149 static int secp256k1_num_is_neg(const secp256k1_num_t *a) {
150     return (a->limbs > 1 || a->data[0] != 0) && a->neg;
151 }
152
153 static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
154     if (a->limbs > b->limbs) {
155         return 1;
156     }
157     if (a->limbs < b->limbs) {
158         return -1;
159     }
160     return mpn_cmp(a->data, b->data, a->limbs);
161 }
162
163 static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) {
164     if (a->limbs > b->limbs) {
165         return 0;
166     }
167     if (a->limbs < b->limbs) {
168         return 0;
169     }
170     if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) {
171         return 0;
172     }
173     return mpn_cmp(a->data, b->data, a->limbs) == 0;
174 }
175
176 static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) {
177     if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */
178         r->neg = a->neg;
179         if (a->limbs >= b->limbs) {
180             secp256k1_num_add_abs(r, a, b);
181         } else {
182             secp256k1_num_add_abs(r, b, a);
183         }
184     } else {
185         if (secp256k1_num_cmp(a, b) > 0) {
186             r->neg = a->neg;
187             secp256k1_num_sub_abs(r, a, b);
188         } else {
189             r->neg = b->neg ^ bneg;
190             secp256k1_num_sub_abs(r, b, a);
191         }
192     }
193 }
194
195 static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
196     secp256k1_num_sanity(a);
197     secp256k1_num_sanity(b);
198     secp256k1_num_subadd(r, a, b, 0);
199 }
200
201 static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
202     secp256k1_num_sanity(a);
203     secp256k1_num_sanity(b);
204     secp256k1_num_subadd(r, a, b, 1);
205 }
206
207 static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
208     mp_limb_t tmp[2*NUM_LIMBS+1];
209     secp256k1_num_sanity(a);
210     secp256k1_num_sanity(b);
211
212     VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1);
213     if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) {
214         r->limbs = 1;
215         r->neg = 0;
216         r->data[0] = 0;
217         return;
218     }
219     if (a->limbs >= b->limbs) {
220         mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs);
221     } else {
222         mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs);
223     }
224     r->limbs = a->limbs + b->limbs;
225     if (r->limbs > 1 && tmp[r->limbs - 1]==0) {
226         r->limbs--;
227     }
228     VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS);
229     mpn_copyi(r->data, tmp, r->limbs);
230     r->neg = a->neg ^ b->neg;
231     memset(tmp, 0, sizeof(tmp));
232 }
233
234 static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
235     int i;
236     if (bits % GMP_NUMB_BITS) {
237         /* Shift within limbs. */
238         mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);
239     }
240     if (bits >= GMP_NUMB_BITS) {
241         /* Shift full limbs. */
242         for (i = 0; i < r->limbs; i++) {
243             int index = i + (bits / GMP_NUMB_BITS);
244             if (index < r->limbs && index < 2*NUM_LIMBS) {
245                 r->data[i] = r->data[index];
246             } else {
247                 r->data[i] = 0;
248             }
249         }
250     }
251     while (r->limbs>1 && r->data[r->limbs-1]==0) {
252         r->limbs--;
253     }
254 }
255
256 static void secp256k1_num_negate(secp256k1_num_t *r) {
257     r->neg ^= 1;
258 }
259
260 #endif
This page took 0.039647 seconds and 4 git commands to generate.