Skip to content

Commit 3e9aff1

Browse files
committed
Add a secp256k1_ecdsa_signature_t type
1 parent 1353ba1 commit 3e9aff1

File tree

7 files changed

+346
-259
lines changed

7 files changed

+346
-259
lines changed

include/secp256k1.h

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,80 @@ int secp256k1_ec_pubkey_serialize(
120120
int compressed
121121
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
122122

123+
/** Data type to hold a parsed ECDSA signature, optionally supporting pubkey
124+
* recovery */
125+
typedef struct {
126+
unsigned char data[65];
127+
} secp256k1_ecdsa_signature_t;
128+
129+
/** Parse a DER ECDSA signature.
130+
* Returns: 1 when the signature could be parsed, 0 otherwise.
131+
* In: ctx: a secp256k1 context object
132+
* input: a pointer to the signature to be parsed
133+
* inputlen: the length of the array pointed to be input
134+
* Out: sig: a pointer to a signature object
135+
*
136+
* Note that this function also supports some violations of DER.
137+
*
138+
* The resulting signature object will not support pubkey recovery.
139+
*/
140+
int secp256k1_ecdsa_signature_parse_der(
141+
const secp256k1_context_t* ctx,
142+
secp256k1_ecdsa_signature_t* sig,
143+
const unsigned char *input,
144+
int inputlen
145+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
146+
147+
/** Parse a compact ECDSA signature (64 bytes + recovery id).
148+
* Returns: 1 when the signature could be parsed, 0 otherwise
149+
* In: ctx: a secp256k1 context object
150+
* input64: a pointer to a 64-byte compact signature
151+
* recid: the recovery id (0, 1, 2 or 3, or -1 for unknown)
152+
* Out: sig: a pointer to a signature object
153+
*
154+
* If recid is not -1, the resulting signature object will support pubkey
155+
* recovery.
156+
*/
157+
int secp256k1_ecdsa_signature_parse_compact(
158+
const secp256k1_context_t* ctx,
159+
secp256k1_ecdsa_signature_t* sig,
160+
const unsigned char *input64,
161+
int recid
162+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
163+
164+
/** Serialize an ECDSA signature in DER format.
165+
* Returns: 1 if enough space was available to serialize, 0 otherwise
166+
* In: ctx: a secp256k1 context object
167+
* sig: a pointer to an initialized signature object
168+
* Out: output: a pointer to an array to store the DER serialization
169+
* In/Out: outputlen: a pointer to a length integer. Initially, this integer
170+
* should be set to the length of output. After the call
171+
* it will be set to the length of the serialization (even
172+
* if 0 was returned).
173+
*/
174+
int secp256k1_ecdsa_signature_serialize_der(
175+
const secp256k1_context_t* ctx,
176+
unsigned char *output,
177+
int *outputlen,
178+
const secp256k1_ecdsa_signature_t* sig
179+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
180+
181+
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
182+
* Returns: 1
183+
* In: ctx: a secp256k1 context object
184+
* sig: a pointer to an initialized signature object (cannot be NULL)
185+
* Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL)
186+
* recid: a pointer to an integer to hold the recovery id (can be NULL).
187+
*
188+
* If recid is not NULL, the signature must support pubkey recovery.
189+
*/
190+
int secp256k1_ecdsa_signature_serialize_compact(
191+
const secp256k1_context_t* ctx,
192+
unsigned char *output64,
193+
int *recid,
194+
const secp256k1_ecdsa_signature_t* sig
195+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
196+
123197
/** Verify an ECDSA signature.
124198
* Returns: 1: correct signature
125199
* 0: incorrect or unparseable signature
@@ -132,10 +206,9 @@ int secp256k1_ec_pubkey_serialize(
132206
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
133207
const secp256k1_context_t* ctx,
134208
const unsigned char *msg32,
135-
const unsigned char *sig,
136-
int siglen,
209+
const secp256k1_ecdsa_signature_t *sig,
137210
const secp256k1_pubkey_t *pubkey
138-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
211+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
139212

140213
/** A pointer to a function to deterministically generate a nonce.
141214
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
@@ -168,16 +241,15 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
168241

169242
/** Create an ECDSA signature.
170243
* Returns: 1: signature created
171-
* 0: the nonce generation function failed, the private key was invalid, or there is not
172-
* enough space in the signature (as indicated by siglen).
244+
* 0: the nonce generation function failed, or the private key was invalid.
173245
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
174246
* msg32: the 32-byte message hash being signed (cannot be NULL)
175247
* seckey: pointer to a 32-byte secret key (cannot be NULL)
176248
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
177249
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
178250
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
179-
* In/Out: siglen: pointer to an int with the length of sig, which will be updated
180-
* to contain the actual signature length (<=72).
251+
*
252+
* The resulting signature will support pubkey recovery.
181253
*
182254
* The sig always has an s value in the lower half of the range (From 0x1
183255
* to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
@@ -208,50 +280,25 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
208280
int secp256k1_ecdsa_sign(
209281
const secp256k1_context_t* ctx,
210282
const unsigned char *msg32,
211-
unsigned char *sig,
212-
int *siglen,
283+
secp256k1_ecdsa_signature_t *sig,
213284
const unsigned char *seckey,
214285
secp256k1_nonce_function_t noncefp,
215286
const void *ndata
216-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
217-
218-
/** Create a compact ECDSA signature (64 byte + recovery id).
219-
* Returns: 1: signature created
220-
* 0: the nonce generation function failed, or the secret key was invalid.
221-
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
222-
* msg32: the 32-byte message hash being signed (cannot be NULL)
223-
* seckey: pointer to a 32-byte secret key (cannot be NULL)
224-
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
225-
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
226-
* Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL)
227-
* In case 0 is returned, the returned signature length will be zero.
228-
* recid: pointer to an int, which will be updated to contain the recovery id (can be NULL)
229-
*/
230-
int secp256k1_ecdsa_sign_compact(
231-
const secp256k1_context_t* ctx,
232-
const unsigned char *msg32,
233-
unsigned char *sig64,
234-
const unsigned char *seckey,
235-
secp256k1_nonce_function_t noncefp,
236-
const void *ndata,
237-
int *recid
238287
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
239288

240-
/** Recover an ECDSA public key from a compact signature.
289+
/** Recover an ECDSA public key from a signature.
241290
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
242291
* 0: otherwise.
243292
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
244293
* msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
245-
* sig64: signature as 64 byte array (cannot be NULL)
246-
* recid: the recovery id (0-3, as returned by ecdsa_sign_compact)
294+
* sig64: pointer to initialized signature that supports pubkey recovery (cannot be NULL)
247295
* Out: pubkey: pointer to the recoved public key (cannot be NULL)
248296
*/
249-
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact(
297+
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
250298
const secp256k1_context_t* ctx,
251299
const unsigned char *msg32,
252-
const unsigned char *sig64,
253-
secp256k1_pubkey_t *pubkey,
254-
int recid
300+
const secp256k1_ecdsa_signature_t *sig,
301+
secp256k1_pubkey_t *pubkey
255302
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
256303

257304
/** Verify an ECDSA secret key.

src/bench_recover.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ void bench_recover(void* arg) {
2323
for (i = 0; i < 20000; i++) {
2424
int j;
2525
int pubkeylen = 33;
26-
CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, &pubkey, i % 2));
26+
secp256k1_ecdsa_signature_t sig;
27+
CHECK(secp256k1_ecdsa_signature_parse_compact(data->ctx, &sig, data->sig, i % 2));
28+
CHECK(secp256k1_ecdsa_recover(data->ctx, data->msg, &sig, &pubkey));
2729
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, 1));
2830
for (j = 0; j < 32; j++) {
2931
data->sig[j + 32] = data->msg[j]; /* Move former message to S. */

src/bench_sign.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ static void bench_sign(void* arg) {
3030
for (i = 0; i < 20000; i++) {
3131
int j;
3232
int recid = 0;
33-
CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid));
33+
secp256k1_ecdsa_signature_t signature;
34+
CHECK(secp256k1_ecdsa_sign(data->ctx, data->msg, &signature, data->key, NULL, NULL));
35+
CHECK(secp256k1_ecdsa_signature_serialize_compact(data->ctx, sig, &recid, &signature));
3436
for (j = 0; j < 32; j++) {
3537
data->msg[j] = sig[j]; /* Move former R to message. */
3638
data->key[j] = sig[j + 32]; /* Move former S to key. */

src/bench_verify.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ static void benchmark_verify(void* arg) {
2727

2828
for (i = 0; i < 20000; i++) {
2929
secp256k1_pubkey_t pubkey;
30+
secp256k1_ecdsa_signature_t sig;
3031
data->sig[data->siglen - 1] ^= (i & 0xFF);
3132
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
3233
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
3334
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));
35+
CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1);
36+
CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, &sig, &pubkey) == (i == 0));
3537
data->sig[data->siglen - 1] ^= (i & 0xFF);
3638
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
3739
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@@ -41,14 +43,16 @@ static void benchmark_verify(void* arg) {
4143
int main(void) {
4244
int i;
4345
secp256k1_pubkey_t pubkey;
46+
secp256k1_ecdsa_signature_t sig;
4447
benchmark_verify_t data;
4548

4649
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
4750

4851
for (i = 0; i < 32; i++) data.msg[i] = 1 + i;
4952
for (i = 0; i < 32; i++) data.key[i] = 33 + i;
5053
data.siglen = 72;
51-
secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL);
54+
CHECK(secp256k1_ecdsa_sign(data.ctx, data.msg, &sig, data.key, NULL, NULL));
55+
CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig));
5256
CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));
5357
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, 1) == 1);
5458

src/ecdsa_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se
118118
while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; }
119119
while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; }
120120
if (*size < 6+lenS+lenR) {
121+
*size = 6 + lenS + lenR;
121122
return 0;
122123
}
123124
*size = 6 + lenS + lenR;

0 commit comments

Comments
 (0)