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
*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
*r
, const secp256k1_num
*a
) {
29 static void secp256k1_num_get_bin(unsigned char *r
, unsigned int rlen
, const secp256k1_num
*a
) {
30 unsigned char tmp
[65];
33 if (a
->limbs
>1 || a
->data
[0] != 0) {
34 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
*r
, const unsigned char *a
, unsigned int alen
) {
47 VERIFY_CHECK(alen
> 0);
48 VERIFY_CHECK(alen
<= 64);
49 len
= mpn_set_str(r
->data
, a
, alen
, 256);
54 VERIFY_CHECK(len
<= NUM_LIMBS
*2);
57 while (r
->limbs
> 1 && r
->data
[r
->limbs
-1]==0) {
62 static void secp256k1_num_add_abs(secp256k1_num
*r
, const secp256k1_num
*a
, const secp256k1_num
*b
) {
63 mp_limb_t c
= mpn_add(r
->data
, a
->data
, a
->limbs
, b
->data
, b
->limbs
);
66 VERIFY_CHECK(r
->limbs
< 2*NUM_LIMBS
);
67 r
->data
[r
->limbs
++] = c
;
71 static void secp256k1_num_sub_abs(secp256k1_num
*r
, const secp256k1_num
*a
, const secp256k1_num
*b
) {
72 mp_limb_t c
= mpn_sub(r
->data
, a
->data
, a
->limbs
, b
->data
, b
->limbs
);
76 while (r
->limbs
> 1 && r
->data
[r
->limbs
-1]==0) {
81 static void secp256k1_num_mod(secp256k1_num
*r
, const secp256k1_num
*m
) {
82 secp256k1_num_sanity(r
);
83 secp256k1_num_sanity(m
);
85 if (r
->limbs
>= m
->limbs
) {
86 mp_limb_t t
[2*NUM_LIMBS
];
87 mpn_tdiv_qr(t
, r
->data
, 0, r
->data
, r
->limbs
, m
->data
, m
->limbs
);
88 memset(t
, 0, sizeof(t
));
90 while (r
->limbs
> 1 && r
->data
[r
->limbs
-1]==0) {
95 if (r
->neg
&& (r
->limbs
> 1 || r
->data
[0] != 0)) {
96 secp256k1_num_sub_abs(r
, m
, r
);
101 static void secp256k1_num_mod_inverse(secp256k1_num
*r
, const secp256k1_num
*a
, const secp256k1_num
*m
) {
103 mp_limb_t g
[NUM_LIMBS
+1];
104 mp_limb_t u
[NUM_LIMBS
+1];
105 mp_limb_t v
[NUM_LIMBS
+1];
108 secp256k1_num_sanity(a
);
109 secp256k1_num_sanity(m
);
111 /** mpn_gcdext computes: (G,S) = gcdext(U,V), where
114 * * U has equal or more limbs than V, and V has no padding
115 * If we set U to be (a padded version of) a, and V = m:
121 VERIFY_CHECK(m
->limbs
<= NUM_LIMBS
);
122 VERIFY_CHECK(m
->data
[m
->limbs
-1] != 0);
123 for (i
= 0; i
< m
->limbs
; i
++) {
124 u
[i
] = (i
< a
->limbs
) ? a
->data
[i
] : 0;
128 gn
= mpn_gcdext(g
, r
->data
, &sn
, u
, m
->limbs
, v
, m
->limbs
);
130 VERIFY_CHECK(gn
== 1);
131 VERIFY_CHECK(g
[0] == 1);
132 r
->neg
= a
->neg
^ m
->neg
;
134 mpn_sub(r
->data
, m
->data
, m
->limbs
, r
->data
, -sn
);
136 while (r
->limbs
> 1 && r
->data
[r
->limbs
-1]==0) {
142 memset(g
, 0, sizeof(g
));
143 memset(u
, 0, sizeof(u
));
144 memset(v
, 0, sizeof(v
));
147 static int secp256k1_num_jacobi(const secp256k1_num
*a
, const secp256k1_num
*b
) {
150 secp256k1_num_sanity(a
);
151 secp256k1_num_sanity(b
);
152 VERIFY_CHECK(!b
->neg
&& (b
->limbs
> 0) && (b
->data
[0] & 1));
154 mpz_inits(ga
, gb
, NULL
);
156 mpz_import(gb
, b
->limbs
, -1, sizeof(mp_limb_t
), 0, 0, b
->data
);
157 mpz_import(ga
, a
->limbs
, -1, sizeof(mp_limb_t
), 0, 0, a
->data
);
162 ret
= mpz_jacobi(ga
, gb
);
164 mpz_clears(ga
, gb
, NULL
);
169 static int secp256k1_num_is_one(const secp256k1_num
*a
) {
170 return (a
->limbs
== 1 && a
->data
[0] == 1);
173 static int secp256k1_num_is_zero(const secp256k1_num
*a
) {
174 return (a
->limbs
== 1 && a
->data
[0] == 0);
177 static int secp256k1_num_is_neg(const secp256k1_num
*a
) {
178 return (a
->limbs
> 1 || a
->data
[0] != 0) && a
->neg
;
181 static int secp256k1_num_cmp(const secp256k1_num
*a
, const secp256k1_num
*b
) {
182 if (a
->limbs
> b
->limbs
) {
185 if (a
->limbs
< b
->limbs
) {
188 return mpn_cmp(a
->data
, b
->data
, a
->limbs
);
191 static int secp256k1_num_eq(const secp256k1_num
*a
, const secp256k1_num
*b
) {
192 if (a
->limbs
> b
->limbs
) {
195 if (a
->limbs
< b
->limbs
) {
198 if ((a
->neg
&& !secp256k1_num_is_zero(a
)) != (b
->neg
&& !secp256k1_num_is_zero(b
))) {
201 return mpn_cmp(a
->data
, b
->data
, a
->limbs
) == 0;
204 static void secp256k1_num_subadd(secp256k1_num
*r
, const secp256k1_num
*a
, const secp256k1_num
*b
, int bneg
) {
205 if (!(b
->neg
^ bneg
^ a
->neg
)) { /* a and b have the same sign */
207 if (a
->limbs
>= b
->limbs
) {
208 secp256k1_num_add_abs(r
, a
, b
);
210 secp256k1_num_add_abs(r
, b
, a
);
213 if (secp256k1_num_cmp(a
, b
) > 0) {
215 secp256k1_num_sub_abs(r
, a
, b
);
217 r
->neg
= b
->neg
^ bneg
;
218 secp256k1_num_sub_abs(r
, b
, a
);
223 static void secp256k1_num_add(secp256k1_num
*r
, const secp256k1_num
*a
, const secp256k1_num
*b
) {
224 secp256k1_num_sanity(a
);
225 secp256k1_num_sanity(b
);
226 secp256k1_num_subadd(r
, a
, b
, 0);
229 static void secp256k1_num_sub(secp256k1_num
*r
, const secp256k1_num
*a
, const secp256k1_num
*b
) {
230 secp256k1_num_sanity(a
);
231 secp256k1_num_sanity(b
);
232 secp256k1_num_subadd(r
, a
, b
, 1);
235 static void secp256k1_num_mul(secp256k1_num
*r
, const secp256k1_num
*a
, const secp256k1_num
*b
) {
236 mp_limb_t tmp
[2*NUM_LIMBS
+1];
237 secp256k1_num_sanity(a
);
238 secp256k1_num_sanity(b
);
240 VERIFY_CHECK(a
->limbs
+ b
->limbs
<= 2*NUM_LIMBS
+1);
241 if ((a
->limbs
==1 && a
->data
[0]==0) || (b
->limbs
==1 && b
->data
[0]==0)) {
247 if (a
->limbs
>= b
->limbs
) {
248 mpn_mul(tmp
, a
->data
, a
->limbs
, b
->data
, b
->limbs
);
250 mpn_mul(tmp
, b
->data
, b
->limbs
, a
->data
, a
->limbs
);
252 r
->limbs
= a
->limbs
+ b
->limbs
;
253 if (r
->limbs
> 1 && tmp
[r
->limbs
- 1]==0) {
256 VERIFY_CHECK(r
->limbs
<= 2*NUM_LIMBS
);
257 mpn_copyi(r
->data
, tmp
, r
->limbs
);
258 r
->neg
= a
->neg
^ b
->neg
;
259 memset(tmp
, 0, sizeof(tmp
));
262 static void secp256k1_num_shift(secp256k1_num
*r
, int bits
) {
263 if (bits
% GMP_NUMB_BITS
) {
264 /* Shift within limbs. */
265 mpn_rshift(r
->data
, r
->data
, r
->limbs
, bits
% GMP_NUMB_BITS
);
267 if (bits
>= GMP_NUMB_BITS
) {
269 /* Shift full limbs. */
270 for (i
= 0; i
< r
->limbs
; i
++) {
271 int index
= i
+ (bits
/ GMP_NUMB_BITS
);
272 if (index
< r
->limbs
&& index
< 2*NUM_LIMBS
) {
273 r
->data
[i
] = r
->data
[index
];
279 while (r
->limbs
>1 && r
->data
[r
->limbs
-1]==0) {
284 static void secp256k1_num_negate(secp256k1_num
*r
) {
288 #endif /* SECP256K1_NUM_REPR_IMPL_H */