]>
Commit | Line | Data |
---|---|---|
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 | 18 | static 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 | 25 | static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) { |
898cecb3 PW |
26 | *r = *a; |
27 | } | |
28 | ||
a4a43d75 | 29 | static 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 | 45 | static 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 | 62 | static 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 | 71 | static 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 | 80 | static 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 | 100 | static 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 | 145 | static 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 | 149 | static 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 | 153 | static 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 | 163 | static 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 | 176 | static 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 | 195 | static 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 | 201 | static 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 | 207 | static 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 | 234 | static 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 | 256 | static void secp256k1_num_negate(secp256k1_num_t *r) { |
898cecb3 | 257 | r->neg ^= 1; |
607884fc PW |
258 | } |
259 | ||
7a4b7691 | 260 | #endif |