]> Git Repo - secp256k1.git/blame - src/num_gmp_impl.h
Implement endomorphism optimization for secp256k1_ecmult_const
[secp256k1.git] / src / num_gmp_impl.h
CommitLineData
71712b27
GM
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 **********************************************************************/
0a433ea2 6
7a4b7691
PW
7#ifndef _SECP256K1_NUM_REPR_IMPL_H_
8#define _SECP256K1_NUM_REPR_IMPL_H_
9
607884fc
PW
10#include <string.h>
11#include <stdlib.h>
12#include <gmp.h>
13
1c7fa133 14#include "util.h"
4adf6b2a 15#include "num.h"
607884fc 16
898cecb3 17#ifdef VERIFY
a4a43d75 18static void secp256k1_num_sanity(const secp256k1_num_t *a) {
1c7fa133 19 VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0));
898cecb3
PW
20}
21#else
22#define secp256k1_num_sanity(a) do { } while(0)
23#endif
607884fc 24
a4a43d75 25static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
898cecb3
PW
26 *r = *a;
27}
28
a4a43d75 29static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
898cecb3 30 unsigned char tmp[65];
404c30a8 31 int len = 0;
792bcdb0 32 int shift = 0;
404c30a8
PW
33 if (a->limbs>1 || a->data[0] != 0) {
34 len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);
35 }
404c30a8 36 while (shift < len && tmp[shift] == 0) shift++;
65a14abb 37 VERIFY_CHECK(len-shift <= (int)rlen);
404c30a8 38 memset(r, 0, rlen - len + shift);
2f6c8019 39 if (len > shift) {
404c30a8 40 memcpy(r + rlen - len + shift, tmp + shift, len - shift);
2f6c8019
GM
41 }
42 memset(tmp, 0, sizeof(tmp));
607884fc
PW
43}
44
a4a43d75 45static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
792bcdb0 46 int len;
1c7fa133
PW
47 VERIFY_CHECK(alen > 0);
48 VERIFY_CHECK(alen <= 64);
792bcdb0 49 len = mpn_set_str(r->data, a, alen, 256);
99f0728f
PW
50 if (len == 0) {
51 r->data[0] = 0;
52 len = 1;
53 }
1c7fa133 54 VERIFY_CHECK(len <= NUM_LIMBS*2);
898cecb3
PW
55 r->limbs = len;
56 r->neg = 0;
26320197
GM
57 while (r->limbs > 1 && r->data[r->limbs-1]==0) {
58 r->limbs--;
59 }
607884fc
PW
60}
61
a4a43d75 62static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
79b0ce6c
PW
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) {
1c7fa133 66 VERIFY_CHECK(r->limbs < 2*NUM_LIMBS);
79b0ce6c
PW
67 r->data[r->limbs++] = c;
68 }
69}
70
a4a43d75 71static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
79b0ce6c 72 mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
1c7fa133 73 VERIFY_CHECK(c == 0);
79b0ce6c 74 r->limbs = a->limbs;
26320197
GM
75 while (r->limbs > 1 && r->data[r->limbs-1]==0) {
76 r->limbs--;
77 }
79b0ce6c
PW
78}
79
a4a43d75 80static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
2f9e831d
PW
81 secp256k1_num_sanity(r);
82 secp256k1_num_sanity(m);
898cecb3 83
2f9e831d
PW
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);
2f6c8019 87 memset(t, 0, sizeof(t));
2f9e831d 88 r->limbs = m->limbs;
26320197
GM
89 while (r->limbs > 1 && r->data[r->limbs-1]==0) {
90 r->limbs--;
91 }
79b0ce6c
PW
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;
898cecb3 97 }
607884fc
PW
98}
99
a4a43d75 100static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
792bcdb0
GM
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;
898cecb3
PW
107 secp256k1_num_sanity(a);
108 secp256k1_num_sanity(m);
109
71712b27
GM
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 */
1c7fa133
PW
120 VERIFY_CHECK(m->limbs <= NUM_LIMBS);
121 VERIFY_CHECK(m->data[m->limbs-1] != 0);
792bcdb0 122 for (i = 0; i < m->limbs; i++) {
898cecb3
PW
123 u[i] = (i < a->limbs) ? a->data[i] : 0;
124 v[i] = m->data[i];
125 }
792bcdb0
GM
126 sn = NUM_LIMBS+1;
127 gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
1c7fa133
PW
128 VERIFY_CHECK(gn == 1);
129 VERIFY_CHECK(g[0] == 1);
898cecb3
PW
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;
26320197
GM
134 while (r->limbs > 1 && r->data[r->limbs-1]==0) {
135 r->limbs--;
136 }
898cecb3
PW
137 } else {
138 r->limbs = sn;
139 }
2f6c8019
GM
140 memset(g, 0, sizeof(g));
141 memset(u, 0, sizeof(u));
142 memset(v, 0, sizeof(v));
607884fc
PW
143}
144
a4a43d75 145static int secp256k1_num_is_zero(const secp256k1_num_t *a) {
898cecb3 146 return (a->limbs == 1 && a->data[0] == 0);
607884fc
PW
147}
148
a4a43d75 149static int secp256k1_num_is_neg(const secp256k1_num_t *a) {
898cecb3 150 return (a->limbs > 1 || a->data[0] != 0) && a->neg;
607884fc
PW
151}
152
a4a43d75 153static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
26320197
GM
154 if (a->limbs > b->limbs) {
155 return 1;
156 }
157 if (a->limbs < b->limbs) {
158 return -1;
159 }
898cecb3 160 return mpn_cmp(a->data, b->data, a->limbs);
607884fc
PW
161}
162
a4a43d75 163static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) {
26320197
GM
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 }
1a749b4a
PW
173 return mpn_cmp(a->data, b->data, a->limbs) == 0;
174}
175
a4a43d75 176static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) {
71712b27 177 if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */
898cecb3
PW
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 }
607884fc
PW
193}
194
a4a43d75 195static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
898cecb3
PW
196 secp256k1_num_sanity(a);
197 secp256k1_num_sanity(b);
898cecb3 198 secp256k1_num_subadd(r, a, b, 0);
607884fc
PW
199}
200
a4a43d75 201static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
898cecb3
PW
202 secp256k1_num_sanity(a);
203 secp256k1_num_sanity(b);
898cecb3 204 secp256k1_num_subadd(r, a, b, 1);
607884fc
PW
205}
206
a4a43d75 207static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
792bcdb0 208 mp_limb_t tmp[2*NUM_LIMBS+1];
898cecb3
PW
209 secp256k1_num_sanity(a);
210 secp256k1_num_sanity(b);
211
1c7fa133 212 VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1);
898cecb3
PW
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 }
26320197 219 if (a->limbs >= b->limbs) {
898cecb3 220 mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs);
26320197 221 } else {
898cecb3 222 mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs);
26320197 223 }
898cecb3 224 r->limbs = a->limbs + b->limbs;
26320197
GM
225 if (r->limbs > 1 && tmp[r->limbs - 1]==0) {
226 r->limbs--;
227 }
1c7fa133 228 VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS);
898cecb3
PW
229 mpn_copyi(r->data, tmp, r->limbs);
230 r->neg = a->neg ^ b->neg;
2f6c8019 231 memset(tmp, 0, sizeof(tmp));
607884fc
PW
232}
233
ff8746d4 234static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
792bcdb0 235 int i;
ff8746d4 236 if (bits % GMP_NUMB_BITS) {
792bcdb0 237 /* Shift within limbs. */
ff8746d4
PW
238 mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);
239 }
240 if (bits >= GMP_NUMB_BITS) {
792bcdb0
GM
241 /* Shift full limbs. */
242 for (i = 0; i < r->limbs; i++) {
ff8746d4
PW
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 }
26320197
GM
251 while (r->limbs>1 && r->data[r->limbs-1]==0) {
252 r->limbs--;
253 }
607884fc
PW
254}
255
a4a43d75 256static void secp256k1_num_negate(secp256k1_num_t *r) {
898cecb3 257 r->neg ^= 1;
607884fc
PW
258}
259
7a4b7691 260#endif
This page took 0.071908 seconds and 4 git commands to generate.