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 **********************************************************************/
7 #ifndef _SECP256K1_NUM_REPR_IMPL_H_
8 #define _SECP256K1_NUM_REPR_IMPL_H_
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));
22 #define secp256k1_num_sanity(a) do { } while(0)
25 static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
29 static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
30 unsigned char tmp[65];
32 if (a->limbs>1 || a->data[0] != 0) {
33 len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);
36 while (shift < len && tmp[shift] == 0) shift++;
37 VERIFY_CHECK(len-shift <= (int)rlen);
38 memset(r, 0, rlen - len + shift);
40 memcpy(r + rlen - len + shift, tmp + shift, len - shift);
42 memset(tmp, 0, sizeof(tmp));
45 static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
46 VERIFY_CHECK(alen > 0);
47 VERIFY_CHECK(alen <= 64);
48 int len = mpn_set_str(r->data, a, alen, 256);
53 VERIFY_CHECK(len <= NUM_LIMBS*2);
56 while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
59 static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
60 mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
63 VERIFY_CHECK(r->limbs < 2*NUM_LIMBS);
64 r->data[r->limbs++] = c;
68 static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
69 mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
72 while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
75 static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
76 secp256k1_num_sanity(r);
77 secp256k1_num_sanity(m);
79 if (r->limbs >= m->limbs) {
80 mp_limb_t t[2*NUM_LIMBS];
81 mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs);
82 memset(t, 0, sizeof(t));
84 while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
87 if (r->neg && (r->limbs > 1 || r->data[0] != 0)) {
88 secp256k1_num_sub_abs(r, m, r);
93 static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
94 secp256k1_num_sanity(a);
95 secp256k1_num_sanity(m);
97 /** mpn_gcdext computes: (G,S) = gcdext(U,V), where
100 * * U has equal or more limbs than V, and V has no padding
101 * If we set U to be (a padded version of) a, and V = m:
107 VERIFY_CHECK(m->limbs <= NUM_LIMBS);
108 VERIFY_CHECK(m->data[m->limbs-1] != 0);
109 mp_limb_t g[NUM_LIMBS+1];
110 mp_limb_t u[NUM_LIMBS+1];
111 mp_limb_t v[NUM_LIMBS+1];
112 for (int i=0; i < m->limbs; i++) {
113 u[i] = (i < a->limbs) ? a->data[i] : 0;
116 mp_size_t sn = NUM_LIMBS+1;
117 mp_size_t gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
118 VERIFY_CHECK(gn == 1);
119 VERIFY_CHECK(g[0] == 1);
120 r->neg = a->neg ^ m->neg;
122 mpn_sub(r->data, m->data, m->limbs, r->data, -sn);
124 while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
128 memset(g, 0, sizeof(g));
129 memset(u, 0, sizeof(u));
130 memset(v, 0, sizeof(v));
133 static int secp256k1_num_is_zero(const secp256k1_num_t *a) {
134 return (a->limbs == 1 && a->data[0] == 0);
137 static int secp256k1_num_is_neg(const secp256k1_num_t *a) {
138 return (a->limbs > 1 || a->data[0] != 0) && a->neg;
141 static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
142 if (a->limbs > b->limbs) return 1;
143 if (a->limbs < b->limbs) return -1;
144 return mpn_cmp(a->data, b->data, a->limbs);
147 static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) {
148 if (a->limbs > b->limbs) return 0;
149 if (a->limbs < b->limbs) return 0;
150 if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) return 0;
151 return mpn_cmp(a->data, b->data, a->limbs) == 0;
154 static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) {
155 if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */
157 if (a->limbs >= b->limbs) {
158 secp256k1_num_add_abs(r, a, b);
160 secp256k1_num_add_abs(r, b, a);
163 if (secp256k1_num_cmp(a, b) > 0) {
165 secp256k1_num_sub_abs(r, a, b);
167 r->neg = b->neg ^ bneg;
168 secp256k1_num_sub_abs(r, b, a);
173 static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
174 secp256k1_num_sanity(a);
175 secp256k1_num_sanity(b);
176 secp256k1_num_subadd(r, a, b, 0);
179 static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
180 secp256k1_num_sanity(a);
181 secp256k1_num_sanity(b);
182 secp256k1_num_subadd(r, a, b, 1);
185 static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
186 secp256k1_num_sanity(a);
187 secp256k1_num_sanity(b);
189 mp_limb_t tmp[2*NUM_LIMBS+1];
190 VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1);
191 if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) {
197 if (a->limbs >= b->limbs)
198 mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs);
200 mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs);
201 r->limbs = a->limbs + b->limbs;
202 if (r->limbs > 1 && tmp[r->limbs - 1]==0) r->limbs--;
203 VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS);
204 mpn_copyi(r->data, tmp, r->limbs);
205 r->neg = a->neg ^ b->neg;
206 memset(tmp, 0, sizeof(tmp));
209 static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
210 if (bits % GMP_NUMB_BITS) {
211 // Shift within limbs.
212 mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);
214 if (bits >= GMP_NUMB_BITS) {
216 for (int i = 0; i < r->limbs; i++) {
217 int index = i + (bits / GMP_NUMB_BITS);
218 if (index < r->limbs && index < 2*NUM_LIMBS) {
219 r->data[i] = r->data[index];
225 while (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
228 static void secp256k1_num_negate(secp256k1_num_t *r) {