Skip to content

Commit

Permalink
bitcoin: hand in a secp256k1_context to all routines.
Browse files Browse the repository at this point in the history
We don't want to re-create them internally, ever.

The test-cli tools are patched to generate them all the time, but
they're not performance critical.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Jan 21, 2016
1 parent cc1b1d7 commit 9aa0eac
Show file tree
Hide file tree
Showing 26 changed files with 215 additions and 150 deletions.
14 changes: 5 additions & 9 deletions bitcoin/base58.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,14 +306,14 @@ char *key_to_base58(const tal_t *ctx, bool test_net, const struct privkey *key)
return tal_strdup(ctx, p);
}

bool key_from_base58(const char *base58, size_t base58_len,
bool key_from_base58(secp256k1_context *secpctx,
const char *base58, size_t base58_len,
bool *test_net, struct privkey *priv, struct pubkey *key)
{
u8 keybuf[1 + 32 + 1 + 4];
u8 csum[4];
BIGNUM bn;
bool compressed;
secp256k1_context *secpctx;
size_t keylen;

BN_init(&bn);
Expand Down Expand Up @@ -347,21 +347,17 @@ bool key_from_base58(const char *base58, size_t base58_len,
/* Copy out secret. */
memcpy(priv->secret, keybuf + 1, sizeof(priv->secret));

secpctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
if (!secp256k1_ec_seckey_verify(secpctx, priv->secret))
goto fail_free_secpctx;
goto fail_free_bn;

/* Get public key, too, since we know if it's compressed. */
if (!pubkey_from_privkey(priv, key,
if (!pubkey_from_privkey(secpctx, priv, key,
compressed ? SECP256K1_EC_COMPRESSED : 0))
goto fail_free_secpctx;
goto fail_free_bn;

BN_free(&bn);
secp256k1_context_destroy(secpctx);
return true;

fail_free_secpctx:
secp256k1_context_destroy(secpctx);
fail_free_bn:
BN_free(&bn);
return false;
Expand Down
4 changes: 3 additions & 1 deletion bitcoin/base58.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define LIGHTNING_BITCOIN_BASE58_H
#include "config.h"

#include "secp256k1.h"
#include <ccan/crypto/ripemd160/ripemd160.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
Expand Down Expand Up @@ -45,7 +46,8 @@ char *base58_with_check(char dest[BASE58_ADDR_MAX_LEN],
u8 buf[1 + sizeof(struct ripemd160) + 4]);

char *key_to_base58(const tal_t *ctx, bool test_net, const struct privkey *key);
bool key_from_base58(const char *base58, size_t base58_len,
bool key_from_base58(secp256k1_context *secpctx,
const char *base58, size_t base58_len,
bool *test_net, struct privkey *priv, struct pubkey *key);

bool raw_decode_base_n(BIGNUM *bn, const char *src, size_t len, int base);
Expand Down
36 changes: 12 additions & 24 deletions bitcoin/pubkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,52 +27,40 @@ size_t pubkey_derlen(const struct pubkey *key)
return len;
}

bool pubkey_from_der(const u8 *der, size_t len, struct pubkey *key)
bool pubkey_from_der(secp256k1_context *secpctx,
const u8 *der, size_t len,
struct pubkey *key)
{
secp256k1_context *secpctx = secp256k1_context_create(0);

if (len > sizeof(key->der))
goto fail_free_secpctx;
return false;

memcpy(key->der, der, len);
if (!secp256k1_ec_pubkey_parse(secpctx, &key->pubkey, key->der, len))
goto fail_free_secpctx;
return false;

secp256k1_context_destroy(secpctx);
return true;

fail_free_secpctx:
secp256k1_context_destroy(secpctx);
return false;
}

/* Pubkey from privkey */
bool pubkey_from_privkey(const struct privkey *privkey,
bool pubkey_from_privkey(secp256k1_context *secpctx,
const struct privkey *privkey,
struct pubkey *key,
unsigned int compressed_flags)
{
secp256k1_context *secpctx;
size_t outlen;

secpctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);

if (!secp256k1_ec_pubkey_create(secpctx, &key->pubkey, privkey->secret))
goto fail_free_secpctx;
return false;

if (!secp256k1_ec_pubkey_serialize(secpctx, key->der, &outlen,
&key->pubkey, compressed_flags))
goto fail_free_secpctx;
return false;
assert(outlen == pubkey_derlen(key));

secp256k1_context_destroy(secpctx);
return true;

fail_free_secpctx:
secp256k1_context_destroy(secpctx);
return false;
}

bool pubkey_from_hexstr(const char *derstr, size_t slen, struct pubkey *key)
bool pubkey_from_hexstr(secp256k1_context *secpctx,
const char *derstr, size_t slen, struct pubkey *key)
{
size_t dlen;
unsigned char der[65];
Expand All @@ -84,7 +72,7 @@ bool pubkey_from_hexstr(const char *derstr, size_t slen, struct pubkey *key)
if (!hex_decode(derstr, slen, der, dlen))
return false;

return pubkey_from_der(der, dlen, key);
return pubkey_from_der(secpctx, der, dlen, key);
}

bool pubkey_eq(const struct pubkey *a, const struct pubkey *b)
Expand Down
9 changes: 6 additions & 3 deletions bitcoin/pubkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@ struct pubkey {
};

/* Convert from hex string of DER (scriptPubKey from validateaddress) */
bool pubkey_from_hexstr(const char *derstr, size_t derlen, struct pubkey *key);
bool pubkey_from_hexstr(secp256k1_context *secpctx,
const char *derstr, size_t derlen, struct pubkey *key);

/* Pubkey from privkey */
bool pubkey_from_privkey(const struct privkey *privkey,
bool pubkey_from_privkey(secp256k1_context *secpctx,
const struct privkey *privkey,
struct pubkey *key,
unsigned int compressed_flags);

/* Pubkey from DER encoding. */
bool pubkey_from_der(const u8 *der, size_t len, struct pubkey *key);
bool pubkey_from_der(secp256k1_context *secpctx,
const u8 *der, size_t len, struct pubkey *key);

/* How many bytes of key->der are valid. */
size_t pubkey_derlen(const struct pubkey *key);
Expand Down
4 changes: 3 additions & 1 deletion bitcoin/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,13 @@ static void add_push_sig(u8 **scriptp, const struct bitcoin_signature *sig)
/* Bitcoin wants DER encoding. */
#ifdef SCRIPTS_USE_DER
u8 der[73];
size_t len = signature_to_der(der, &sig->sig);
secp256k1_context *secpctx = secp256k1_context_create(0);
size_t len = signature_to_der(secpctx, der, &sig->sig);

/* Append sighash type */
der[len++] = sig->stype;
add_push_bytes(scriptp, der, len);
secp256k1_context_destroy(secpctx);
#else /* Alpha uses raw encoding */
u8 with_sighash[sizeof(sig->sig) + 1];
memcpy(with_sighash, &sig->sig, sizeof(sig->sig));
Expand Down
45 changes: 18 additions & 27 deletions bitcoin/signature.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,12 @@ static void dump_tx(const char *msg,
}
#endif

bool sign_hash(const struct privkey *privkey,
void sign_hash(secp256k1_context *secpctx,
const struct privkey *privkey,
const struct sha256_double *h,
struct signature *s)
{
secp256k1_context *secpctx;
bool ok;

secpctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
if (!secpctx)
return false;

#ifdef USE_SCHNORR
ok = secp256k1_schnorr_sign(secpctx,
Expand All @@ -98,9 +94,7 @@ bool sign_hash(const struct privkey *privkey,
h->sha.u.u8,
privkey->secret, NULL, NULL);
#endif

secp256k1_context_destroy(secpctx);
return ok;
assert(ok);
}

/* Only does SIGHASH_ALL */
Expand Down Expand Up @@ -133,7 +127,8 @@ static void sha256_tx_one_input(struct bitcoin_tx *tx,
}

/* Only does SIGHASH_ALL */
bool sign_tx_input(struct bitcoin_tx *tx,
void sign_tx_input(secp256k1_context *secpctx,
struct bitcoin_tx *tx,
unsigned int in,
const u8 *subscript, size_t subscript_len,
const struct privkey *privkey, const struct pubkey *key,
Expand All @@ -143,19 +138,15 @@ bool sign_tx_input(struct bitcoin_tx *tx,

sha256_tx_one_input(tx, in, subscript, subscript_len, &hash);
dump_tx("Signing", tx, in, subscript, subscript_len, key, &hash);
return sign_hash(privkey, &hash, sig);
sign_hash(secpctx, privkey, &hash, sig);
}

bool check_signed_hash(const struct sha256_double *hash,
bool check_signed_hash(secp256k1_context *secpctx,
const struct sha256_double *hash,
const struct signature *signature,
const struct pubkey *key)
{
int ret;
secp256k1_context *secpctx;

secpctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
if (!secpctx)
return false;

#ifdef USE_SCHNORR
ret = secp256k1_schnorr_verify(secpctx, signature->schnorr,
Expand All @@ -165,12 +156,11 @@ bool check_signed_hash(const struct sha256_double *hash,
&signature->sig,
hash->sha.u.u8, &key->pubkey);
#endif

secp256k1_context_destroy(secpctx);
return ret == 1;
}

bool check_tx_sig(struct bitcoin_tx *tx, size_t input_num,
bool check_tx_sig(secp256k1_context *secpctx,
struct bitcoin_tx *tx, size_t input_num,
const u8 *redeemscript, size_t redeemscript_len,
const struct pubkey *key,
const struct bitcoin_signature *sig)
Expand All @@ -187,14 +177,15 @@ bool check_tx_sig(struct bitcoin_tx *tx, size_t input_num,
if (sig->stype != SIGHASH_ALL)
return false;

ret = check_signed_hash(&hash, &sig->sig, key);
ret = check_signed_hash(secpctx, &hash, &sig->sig, key);
if (!ret)
dump_tx("Sig failed", tx, input_num,
redeemscript, redeemscript_len, key, &hash);
return ret;
}

bool check_2of2_sig(struct bitcoin_tx *tx, size_t input_num,
bool check_2of2_sig(secp256k1_context *secpctx,
struct bitcoin_tx *tx, size_t input_num,
const u8 *redeemscript, size_t redeemscript_len,
const struct pubkey *key1, const struct pubkey *key2,
const struct bitcoin_signature *sig1,
Expand All @@ -210,8 +201,8 @@ bool check_2of2_sig(struct bitcoin_tx *tx, size_t input_num,
if (sig1->stype != SIGHASH_ALL || sig2->stype != SIGHASH_ALL)
return false;

return check_signed_hash(&hash, &sig1->sig, key1)
&& check_signed_hash(&hash, &sig2->sig, key2);
return check_signed_hash(secpctx, &hash, &sig1->sig, key1)
&& check_signed_hash(secpctx, &hash, &sig2->sig, key2);
}

#ifndef USE_SCHNORR
Expand Down Expand Up @@ -287,12 +278,12 @@ static bool IsValidSignatureEncoding(const unsigned char sig[], size_t len)
return true;
}

size_t signature_to_der(u8 der[72], const struct signature *sig)
size_t signature_to_der(secp256k1_context *secpctx,
u8 der[72], const struct signature *sig)
{
size_t len = 72;
secp256k1_context *ctx = secp256k1_context_create(0);

secp256k1_ecdsa_signature_serialize_der(ctx, der, &len, &sig->sig);
secp256k1_ecdsa_signature_serialize_der(secpctx, der, &len, &sig->sig);

/* IsValidSignatureEncoding() expect extra byte for sighash */
assert(IsValidSignatureEncoding(der, len + 1));
Expand Down
18 changes: 12 additions & 6 deletions bitcoin/signature.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,33 @@ struct privkey;
struct bitcoin_tx_output;
struct bitcoin_signature;

bool sign_hash(const struct privkey *p,
void sign_hash(secp256k1_context *secpctx,
const struct privkey *p,
const struct sha256_double *h,
struct signature *s);

bool check_signed_hash(const struct sha256_double *hash,
bool check_signed_hash(secp256k1_context *secpctx,
const struct sha256_double *hash,
const struct signature *signature,
const struct pubkey *key);

/* All tx input scripts must be set to 0 len. */
bool sign_tx_input(struct bitcoin_tx *tx,
void sign_tx_input(secp256k1_context *secpctx,
struct bitcoin_tx *tx,
unsigned int in,
const u8 *subscript, size_t subscript_len,
const struct privkey *privkey, const struct pubkey *pubkey,
struct signature *sig);

/* Does this sig sign the tx with this input for this pubkey. */
bool check_tx_sig(struct bitcoin_tx *tx, size_t input_num,
bool check_tx_sig(secp256k1_context *secpctx,
struct bitcoin_tx *tx, size_t input_num,
const u8 *redeemscript, size_t redeemscript_len,
const struct pubkey *key,
const struct bitcoin_signature *sig);

bool check_2of2_sig(struct bitcoin_tx *tx, size_t input_num,
bool check_2of2_sig(secp256k1_context *secpctx,
struct bitcoin_tx *tx, size_t input_num,
const u8 *redeemscript, size_t redeemscript_len,
const struct pubkey *key1, const struct pubkey *key2,
const struct bitcoin_signature *sig1,
Expand All @@ -60,7 +65,8 @@ bool sig_valid(const struct signature *s);

#ifndef USE_SCHNORR
/* Give DER encoding of signature: returns length used (<= 72). */
size_t signature_to_der(u8 der[72], const struct signature *s);
size_t signature_to_der(secp256k1_context *secpctx,
u8 der[72], const struct signature *s);
#endif

#endif /* LIGHTNING_BITCOIN_SIGNATURE_H */
7 changes: 4 additions & 3 deletions close_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
#include "permute_tx.h"
#include "protobuf_convert.h"

struct bitcoin_tx *create_close_tx(const tal_t *ctx,
struct bitcoin_tx *create_close_tx(secp256k1_context *secpctx,
const tal_t *ctx,
OpenChannel *ours,
OpenChannel *theirs,
OpenAnchor *anchor,
Expand All @@ -26,9 +27,9 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx,
tx->input[0].input_amount = anchor->amount;

/* Outputs goes to final pubkey */
if (!proto_to_pubkey(ours->final_key, &ourkey))
if (!proto_to_pubkey(secpctx, ours->final_key, &ourkey))
return tal_free(tx);
if (!proto_to_pubkey(theirs->final_key, &theirkey))
if (!proto_to_pubkey(secpctx, theirs->final_key, &theirkey))
return tal_free(tx);


Expand Down
4 changes: 3 additions & 1 deletion close_tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
#define LIGHTNING_CLOSE_TX_H
#include "config.h"
#include "lightning.pb-c.h"
#include "secp256k1.h"
#include <ccan/tal/tal.h>

struct sha256_double;

/* Create close tx to spend the anchor tx output; doesn't fill in
* input scriptsig. */
struct bitcoin_tx *create_close_tx(const tal_t *ctx,
struct bitcoin_tx *create_close_tx(secp256k1_context *secpctx,
const tal_t *ctx,
OpenChannel *ours,
OpenChannel *theirs,
OpenAnchor *anchor,
Expand Down
Loading

0 comments on commit 9aa0eac

Please sign in to comment.