]>
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 | **********************************************************************/ | |
e2f71f1e PW |
6 | |
7 | #ifndef _SECP256K1_ECKEY_IMPL_H_ | |
8 | #define _SECP256K1_ECKEY_IMPL_H_ | |
9 | ||
10 | #include "eckey.h" | |
11 | ||
f24041d6 | 12 | #include "scalar.h" |
e2f71f1e PW |
13 | #include "field.h" |
14 | #include "group.h" | |
15 | #include "ecmult_gen.h" | |
16 | ||
a4a43d75 | 17 | static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) { |
e2f71f1e PW |
18 | if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { |
19 | secp256k1_fe_t x; | |
39bd94d8 | 20 | return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03); |
e2f71f1e PW |
21 | } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { |
22 | secp256k1_fe_t x, y; | |
d907ebc0 PW |
23 | if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { |
24 | return 0; | |
25 | } | |
e2f71f1e | 26 | secp256k1_ge_set_xy(elem, &x, &y); |
26320197 | 27 | if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) { |
e2f71f1e | 28 | return 0; |
26320197 | 29 | } |
39bd94d8 | 30 | return secp256k1_ge_is_valid_var(elem); |
e2f71f1e PW |
31 | } else { |
32 | return 0; | |
33 | } | |
34 | } | |
35 | ||
bbe67d8b PW |
36 | static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) { |
37 | if (secp256k1_ge_is_infinity(elem)) { | |
38 | return 0; | |
39 | } | |
39bd94d8 PW |
40 | secp256k1_fe_normalize_var(&elem->x); |
41 | secp256k1_fe_normalize_var(&elem->y); | |
e2f71f1e PW |
42 | secp256k1_fe_get_b32(&pub[1], &elem->x); |
43 | if (compressed) { | |
44 | *size = 33; | |
45 | pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); | |
46 | } else { | |
47 | *size = 65; | |
48 | pub[0] = 0x04; | |
49 | secp256k1_fe_get_b32(&pub[33], &elem->y); | |
50 | } | |
bbe67d8b | 51 | return 1; |
e2f71f1e PW |
52 | } |
53 | ||
a4a43d75 | 54 | static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen) { |
792bcdb0 | 55 | unsigned char c[32] = {0}; |
e2f71f1e | 56 | const unsigned char *end = privkey + privkeylen; |
792bcdb0 GM |
57 | int lenb = 0; |
58 | int len = 0; | |
59 | int overflow = 0; | |
71712b27 | 60 | /* sequence header */ |
26320197 | 61 | if (end < privkey+1 || *privkey != 0x30) { |
e2f71f1e | 62 | return 0; |
26320197 | 63 | } |
e2f71f1e | 64 | privkey++; |
71712b27 | 65 | /* sequence length constructor */ |
26320197 | 66 | if (end < privkey+1 || !(*privkey & 0x80)) { |
e2f71f1e | 67 | return 0; |
26320197 | 68 | } |
e2f71f1e | 69 | lenb = *privkey & ~0x80; privkey++; |
26320197 | 70 | if (lenb < 1 || lenb > 2) { |
e2f71f1e | 71 | return 0; |
26320197 GM |
72 | } |
73 | if (end < privkey+lenb) { | |
e2f71f1e | 74 | return 0; |
26320197 | 75 | } |
71712b27 | 76 | /* sequence length */ |
e2f71f1e PW |
77 | len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); |
78 | privkey += lenb; | |
26320197 | 79 | if (end < privkey+len) { |
e2f71f1e | 80 | return 0; |
26320197 | 81 | } |
71712b27 | 82 | /* sequence element 0: version number (=1) */ |
26320197 | 83 | if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { |
e2f71f1e | 84 | return 0; |
26320197 | 85 | } |
e2f71f1e | 86 | privkey += 3; |
71712b27 | 87 | /* sequence element 1: octet string, up to 32 bytes */ |
26320197 | 88 | if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { |
e2f71f1e | 89 | return 0; |
26320197 | 90 | } |
eca6cdb1 PW |
91 | memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]); |
92 | secp256k1_scalar_set_b32(key, c, &overflow); | |
93 | memset(c, 0, 32); | |
a9f5c8b8 | 94 | return !overflow; |
e2f71f1e PW |
95 | } |
96 | ||
a9b6595e | 97 | static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) { |
e2f71f1e | 98 | secp256k1_gej_t rp; |
e2f71f1e | 99 | secp256k1_ge_t r; |
792bcdb0 | 100 | int pubkeylen = 0; |
a9b6595e | 101 | secp256k1_ecmult_gen(ctx, &rp, key); |
e2f71f1e PW |
102 | secp256k1_ge_set_gej(&r, &rp); |
103 | if (compressed) { | |
104 | static const unsigned char begin[] = { | |
105 | 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 | |
106 | }; | |
107 | static const unsigned char middle[] = { | |
108 | 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, | |
109 | 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | |
110 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | |
111 | 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, | |
112 | 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, | |
113 | 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, | |
114 | 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | |
115 | 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, | |
116 | 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 | |
117 | }; | |
118 | unsigned char *ptr = privkey; | |
119 | memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); | |
eca6cdb1 | 120 | secp256k1_scalar_get_b32(ptr, key); ptr += 32; |
e2f71f1e | 121 | memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); |
bbe67d8b PW |
122 | if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) { |
123 | return 0; | |
124 | } | |
125 | ptr += pubkeylen; | |
e2f71f1e PW |
126 | *privkeylen = ptr - privkey; |
127 | } else { | |
128 | static const unsigned char begin[] = { | |
129 | 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 | |
130 | }; | |
131 | static const unsigned char middle[] = { | |
132 | 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, | |
133 | 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | |
134 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | |
135 | 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, | |
136 | 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, | |
137 | 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, | |
138 | 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, | |
139 | 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, | |
140 | 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | |
141 | 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, | |
142 | 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 | |
143 | }; | |
144 | unsigned char *ptr = privkey; | |
145 | memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); | |
eca6cdb1 | 146 | secp256k1_scalar_get_b32(ptr, key); ptr += 32; |
e2f71f1e | 147 | memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); |
bbe67d8b PW |
148 | if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) { |
149 | return 0; | |
150 | } | |
151 | ptr += pubkeylen; | |
e2f71f1e PW |
152 | *privkeylen = ptr - privkey; |
153 | } | |
154 | return 1; | |
155 | } | |
156 | ||
a4a43d75 | 157 | static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { |
a9f5c8b8 | 158 | secp256k1_scalar_add(key, key, tweak); |
26320197 | 159 | if (secp256k1_scalar_is_zero(key)) { |
eb74c36b | 160 | return 0; |
26320197 | 161 | } |
eb74c36b PW |
162 | return 1; |
163 | } | |
164 | ||
a9b6595e | 165 | static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { |
eb74c36b | 166 | secp256k1_gej_t pt; |
f24041d6 | 167 | secp256k1_scalar_t one; |
792bcdb0 | 168 | secp256k1_gej_set_ge(&pt, key); |
f24041d6 | 169 | secp256k1_scalar_set_int(&one, 1); |
a9b6595e | 170 | secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); |
eb74c36b | 171 | |
26320197 | 172 | if (secp256k1_gej_is_infinity(&pt)) { |
eb74c36b | 173 | return 0; |
26320197 | 174 | } |
eb74c36b PW |
175 | secp256k1_ge_set_gej(key, &pt); |
176 | return 1; | |
177 | } | |
178 | ||
a4a43d75 | 179 | static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { |
26320197 | 180 | if (secp256k1_scalar_is_zero(tweak)) { |
eb74c36b | 181 | return 0; |
26320197 | 182 | } |
eb74c36b | 183 | |
a9f5c8b8 | 184 | secp256k1_scalar_mul(key, key, tweak); |
eb74c36b PW |
185 | return 1; |
186 | } | |
187 | ||
a9b6595e | 188 | static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { |
792bcdb0 GM |
189 | secp256k1_scalar_t zero; |
190 | secp256k1_gej_t pt; | |
26320197 | 191 | if (secp256k1_scalar_is_zero(tweak)) { |
eb74c36b | 192 | return 0; |
26320197 | 193 | } |
eb74c36b | 194 | |
f24041d6 | 195 | secp256k1_scalar_set_int(&zero, 0); |
eb74c36b | 196 | secp256k1_gej_set_ge(&pt, key); |
a9b6595e | 197 | secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero); |
eb74c36b PW |
198 | secp256k1_ge_set_gej(key, &pt); |
199 | return 1; | |
200 | } | |
201 | ||
e2f71f1e | 202 | #endif |