Skip to content

Commit 23cfa91

Browse files
committed
Introduce secp256k1_pubkey_t type
1 parent 4c63780 commit 23cfa91

File tree

5 files changed

+216
-250
lines changed

5 files changed

+216
-250
lines changed

include/secp256k1.h

Lines changed: 63 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -74,25 +74,70 @@ void secp256k1_context_destroy(
7474
secp256k1_context_t* ctx
7575
) SECP256K1_ARG_NONNULL(1);
7676

77+
/** Data type to hold a parsed and valid public key.
78+
This data type should be considered opaque to the user, and only created
79+
through API functions. It is not guaranteed to be compatible between
80+
different implementations. If you need to convert to a format suitable
81+
for storage or transmission, use secp256k1_ec_pubkey_serialize and
82+
secp256k1_ec_pubkey_parse.
83+
*/
84+
typedef struct {
85+
unsigned char data[64];
86+
} secp256k1_pubkey_t;
87+
88+
/** Parse a variable-length public key into the pubkey object.
89+
* Returns: 1 if the public key was fully valid.
90+
* 0 if the public key could not be parsed or is invalid.
91+
* In: ctx: a secp256k1 context object.
92+
* input: pointer to a serialized public key
93+
* inputlen: length of the array pointed to by input
94+
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
95+
* parsed version of input. If not, its value is undefined.
96+
* This function supports parsing compressed (33 bytes, header byte 0x02 or
97+
* 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header
98+
* byte 0x06 or 0x07) format public keys.
99+
*/
100+
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
101+
const secp256k1_context_t* ctx,
102+
secp256k1_pubkey_t* pubkey,
103+
const unsigned char *input,
104+
int inputlen
105+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
106+
107+
/** Serialize a pubkey object into a serialized byte sequence.
108+
* Returns: 1 always.
109+
* In: ctx: a secp256k1 context object.
110+
* pubkey: a pointer to a secp256k1_pubkey_t containing an initialized
111+
* public key.
112+
* compressed: whether to serialize in compressed format.
113+
* Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if
114+
* compressed==1) byte array to place the serialized key in.
115+
* outputlen: a pointer to an integer which will contain the serialized
116+
* size.
117+
*/
118+
int secp256k1_ec_pubkey_serialize(
119+
const secp256k1_context_t* ctx,
120+
unsigned char *output,
121+
int *outputlen,
122+
const secp256k1_pubkey_t* pubkey,
123+
int compressed
124+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
125+
77126
/** Verify an ECDSA signature.
78127
* Returns: 1: correct signature
79-
* 0: incorrect signature
80-
* -1: invalid public key
81-
* -2: invalid signature
128+
* 0: incorrect or unparseable signature
82129
* In: ctx: a secp256k1 context object, initialized for verification.
83130
* msg32: the 32-byte message hash being verified (cannot be NULL)
84131
* sig: the signature being verified (cannot be NULL)
85132
* siglen: the length of the signature
86-
* pubkey: the public key to verify with (cannot be NULL)
87-
* pubkeylen: the length of pubkey
133+
* pubkey: pointer to an initialized public key to verify with (cannot be NULL)
88134
*/
89135
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
90136
const secp256k1_context_t* ctx,
91137
const unsigned char *msg32,
92138
const unsigned char *sig,
93139
int siglen,
94-
const unsigned char *pubkey,
95-
int pubkeylen
140+
const secp256k1_pubkey_t *pubkey
96141
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
97142

98143
/** A pointer to a function to deterministically generate a nonce.
@@ -124,7 +169,6 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979;
124169
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
125170
extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
126171

127-
128172
/** Create an ECDSA signature.
129173
* Returns: 1: signature created
130174
* 0: the nonce generation function failed, the private key was invalid, or there is not
@@ -202,20 +246,16 @@ int secp256k1_ecdsa_sign_compact(
202246
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
203247
* msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
204248
* sig64: signature as 64 byte array (cannot be NULL)
205-
* compressed: whether to recover a compressed or uncompressed pubkey
206249
* recid: the recovery id (0-3, as returned by ecdsa_sign_compact)
207-
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL)
208-
* pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL)
250+
* Out: pubkey: pointer to the recoved public key (cannot be NULL)
209251
*/
210252
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact(
211253
const secp256k1_context_t* ctx,
212254
const unsigned char *msg32,
213255
const unsigned char *sig64,
214-
unsigned char *pubkey,
215-
int *pubkeylen,
216-
int compressed,
256+
secp256k1_pubkey_t *pubkey,
217257
int recid
218-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
258+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
219259

220260
/** Verify an ECDSA secret key.
221261
* Returns: 1: secret key is valid
@@ -228,71 +268,18 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
228268
const unsigned char *seckey
229269
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
230270

231-
/** Just validate a public key.
232-
* Returns: 1: public key is valid
233-
* 0: public key is invalid
234-
* In: ctx: pointer to a context object (cannot be NULL)
235-
* pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL).
236-
* pubkeylen: length of pubkey
237-
*/
238-
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify(
239-
const secp256k1_context_t* ctx,
240-
const unsigned char *pubkey,
241-
int pubkeylen
242-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
243-
244271
/** Compute the public key for a secret key.
245272
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
246-
* compressed: whether the computed public key should be compressed
247273
* seckey: pointer to a 32-byte private key (cannot be NULL)
248-
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
249-
* area to store the public key (cannot be NULL)
250-
* pubkeylen: pointer to int that will be updated to contains the pubkey's
251-
* length (cannot be NULL)
274+
* Out: pubkey: pointer to the created public key (cannot be NULL)
252275
* Returns: 1: secret was valid, public key stores
253276
* 0: secret was invalid, try again
254277
*/
255278
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
256279
const secp256k1_context_t* ctx,
257-
unsigned char *pubkey,
258-
int *pubkeylen,
259-
const unsigned char *seckey,
260-
int compressed
261-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
262-
263-
/** Compress a public key.
264-
* In: ctx: pointer to a context object (cannot be NULL)
265-
* pubkeyin: pointer to a 33-byte or 65-byte public key (cannot be NULL)
266-
* Out: pubkeyout: pointer to a 33-byte array to put the compressed public key (cannot be NULL)
267-
* May alias pubkeyin.
268-
* pubkeylen: pointer to the size of the public key pointed to by pubkeyin (cannot be NULL)
269-
* It will be updated to reflect the size of the public key in pubkeyout.
270-
* Returns: 0: pubkeyin was invalid
271-
* 1: pubkeyin was valid, and pubkeyout is its compressed version
272-
*/
273-
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_compress(
274-
const secp256k1_context_t* ctx,
275-
const unsigned char *pubkeyin,
276-
unsigned char *pubkeyout,
277-
int *pubkeylen
278-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
279-
280-
/** Decompress a public key.
281-
* In: ctx: pointer to a context object (cannot be NULL)
282-
* pubkeyin: pointer to a 33-byte or 65-byte public key (cannot be NULL)
283-
* Out: pubkeyout: pointer to a 65-byte array to put the decompressed public key (cannot be NULL)
284-
* May alias pubkeyin.
285-
* pubkeylen: pointer to the size of the public key pointed to by pubkeyin (cannot be NULL)
286-
* It will be updated to reflect the size of the public key in pubkeyout.
287-
* Returns: 0: pubkeyin was invalid
288-
* 1: pubkeyin was valid, and pubkeyout is its decompressed version
289-
*/
290-
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress(
291-
const secp256k1_context_t* ctx,
292-
const unsigned char *pubkeyin,
293-
unsigned char *pubkeyout,
294-
int *pubkeylen
295-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
280+
secp256k1_pubkey_t *pubkey,
281+
const unsigned char *seckey
282+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
296283

297284
/** Export a private key in DER format.
298285
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
@@ -325,10 +312,9 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
325312
*/
326313
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
327314
const secp256k1_context_t* ctx,
328-
unsigned char *pubkey,
329-
int pubkeylen,
315+
secp256k1_pubkey_t *pubkey,
330316
const unsigned char *tweak
331-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
317+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
332318

333319
/** Tweak a private key by multiplying it with tweak. */
334320
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
@@ -342,10 +328,9 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
342328
*/
343329
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
344330
const secp256k1_context_t* ctx,
345-
unsigned char *pubkey,
346-
int pubkeylen,
331+
secp256k1_pubkey_t *pubkey,
347332
const unsigned char *tweak
348-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
333+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
349334

350335
/** Updates the context randomization.
351336
* Returns: 1: randomization successfully updated

src/bench_recover.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@ typedef struct {
1717
void bench_recover(void* arg) {
1818
int i;
1919
bench_recover_t *data = (bench_recover_t*)arg;
20-
unsigned char pubkey[33];
20+
secp256k1_pubkey_t pubkey;
21+
unsigned char pubkeyc[33];
2122

2223
for (i = 0; i < 20000; i++) {
2324
int j;
2425
int pubkeylen = 33;
25-
CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2));
26+
CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, &pubkey, i % 2));
27+
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, 1));
2628
for (j = 0; j < 32; j++) {
2729
data->sig[j + 32] = data->msg[j]; /* Move former message to S. */
2830
data->msg[j] = data->sig[j]; /* Move former R to message. */
29-
data->sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
31+
data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
3032
}
3133
}
3234
}

src/bench_verify.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ static void benchmark_verify(void* arg) {
2626
benchmark_verify_t* data = (benchmark_verify_t*)arg;
2727

2828
for (i = 0; i < 20000; i++) {
29+
secp256k1_pubkey_t pubkey;
2930
data->sig[data->siglen - 1] ^= (i & 0xFF);
3031
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
3132
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
32-
CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0));
33+
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1);
34+
CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, &pubkey) == (i == 0));
3335
data->sig[data->siglen - 1] ^= (i & 0xFF);
3436
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
3537
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@@ -38,6 +40,7 @@ static void benchmark_verify(void* arg) {
3840

3941
int main(void) {
4042
int i;
43+
secp256k1_pubkey_t pubkey;
4144
benchmark_verify_t data;
4245

4346
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
@@ -46,8 +49,8 @@ int main(void) {
4649
for (i = 0; i < 32; i++) data.key[i] = 33 + i;
4750
data.siglen = 72;
4851
secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL);
49-
data.pubkeylen = 33;
50-
CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1));
52+
CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));
53+
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, 1) == 1);
5154

5255
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
5356

0 commit comments

Comments
 (0)