Browse Source

Use pubkey structures in bitcoin_script, rather than protobufs.

This ensures we do checking beforehand, and keeps abstractions clear.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 10 years ago
parent
commit
f911b2b6df
  1. 10
      anchor.c
  2. 59
      bitcoin_script.c
  3. 12
      bitcoin_script.h
  4. 11
      commit_tx.c

10
anchor.c

@ -4,6 +4,7 @@
#include "pkt.h" #include "pkt.h"
#include "permute_tx.h" #include "permute_tx.h"
#include "bitcoin_script.h" #include "bitcoin_script.h"
#include "pubkey.h"
#include <ccan/err/err.h> #include <ccan/err/err.h>
struct bitcoin_tx *anchor_tx_create(const tal_t *ctx, struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
@ -15,6 +16,7 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
struct bitcoin_tx *tx; struct bitcoin_tx *tx;
u8 *redeemscript; u8 *redeemscript;
size_t *inmap, *outmap; size_t *inmap, *outmap;
struct pubkey key1, key2;
if (add_overflows_size_t(o1->anchor->n_inputs, o2->anchor->n_inputs)) if (add_overflows_size_t(o1->anchor->n_inputs, o2->anchor->n_inputs))
return NULL; return NULL;
@ -49,9 +51,13 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
if (add_overflows_u64(o1->anchor->total, o2->anchor->total)) if (add_overflows_u64(o1->anchor->total, o2->anchor->total))
return tal_free(tx); return tal_free(tx);
/* Pubkeys both valid, right? */
if (!proto_to_pubkey(o1->anchor->pubkey, &key1)
|| !proto_to_pubkey(o2->anchor->pubkey, &key2))
return tal_free(tx);
/* Make the 2 of 2 payment for the commitment txs. */ /* Make the 2 of 2 payment for the commitment txs. */
redeemscript = bitcoin_redeem_2of2(tx, o1->anchor->pubkey, redeemscript = bitcoin_redeem_2of2(tx, &key1, &key2);
o2->anchor->pubkey);
tx->output[0].amount = o1->anchor->total + o2->anchor->total; tx->output[0].amount = o1->anchor->total + o2->anchor->total;
tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript); tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript);
tx->output[0].script_length = tal_count(tx->output[0].script); tx->output[0].script_length = tal_count(tx->output[0].script);

59
bitcoin_script.c

@ -2,6 +2,7 @@
#include "bitcoin_address.h" #include "bitcoin_address.h"
#include "pkt.h" #include "pkt.h"
#include "signature.h" #include "signature.h"
#include "pubkey.h"
#include <openssl/ripemd.h> #include <openssl/ripemd.h>
#include <ccan/endian/endian.h> #include <ccan/endian/endian.h>
#include <ccan/crypto/sha256/sha256.h> #include <ccan/crypto/sha256/sha256.h>
@ -60,6 +61,11 @@ static void add_push_bytes(u8 **scriptp, const void *mem, size_t len)
add(scriptp, mem, len); add(scriptp, mem, len);
} }
static void add_push_key(u8 **scriptp, const struct pubkey *key)
{
add_push_bytes(scriptp, key->key, pubkey_len(key));
}
/* Bitcoin wants DER encoding. */ /* Bitcoin wants DER encoding. */
static void add_push_sig(u8 **scriptp, const struct signature *sig) static void add_push_sig(u8 **scriptp, const struct signature *sig)
{ {
@ -81,39 +87,28 @@ static void add_push_sig(u8 **scriptp, const struct signature *sig)
/* FIXME: permute? */ /* FIXME: permute? */
/* Is a < b? (If equal we don't care) */ /* Is a < b? (If equal we don't care) */
static bool key_less(const BitcoinPubkey *a, const BitcoinPubkey *b) static bool key_less(const struct pubkey *a, const struct pubkey *b)
{ {
size_t len; /* Shorter one wins. */
int cmp; if (pubkey_len(a) != pubkey_len(b))
return pubkey_len(a) < pubkey_len(b);
if (a->key.len < b->key.len)
len = a->key.len;
else
len = b->key.len;
cmp = memcmp(a->key.data, b->key.data, len);
if (cmp < 0)
return true;
else if (cmp > 0)
return false;
/* Corner case: if it's shorter, it's less. */ return memcmp(a->key, b->key, pubkey_len(a)) < 0;
return a->key.len < b->key.len;
} }
/* tal_count() gives the length of the script. */ /* tal_count() gives the length of the script. */
u8 *bitcoin_redeem_2of2(const tal_t *ctx, u8 *bitcoin_redeem_2of2(const tal_t *ctx,
const BitcoinPubkey *key1, const struct pubkey *key1,
const BitcoinPubkey *key2) const struct pubkey *key2)
{ {
u8 *script = tal_arr(ctx, u8, 0); u8 *script = tal_arr(ctx, u8, 0);
add_op(&script, OP_LITERAL(2)); add_op(&script, OP_LITERAL(2));
if (key_less(key1, key2)) { if (key_less(key1, key2)) {
add_push_bytes(&script, key1->key.data, key1->key.len); add_push_key(&script, key1);
add_push_bytes(&script, key2->key.data, key2->key.len); add_push_key(&script, key2);
} else { } else {
add_push_bytes(&script, key2->key.data, key2->key.len); add_push_key(&script, key2);
add_push_bytes(&script, key1->key.data, key1->key.len); add_push_key(&script, key1);
} }
add_op(&script, OP_LITERAL(2)); add_op(&script, OP_LITERAL(2));
add_op(&script, OP_CHECKMULTISIG); add_op(&script, OP_CHECKMULTISIG);
@ -121,10 +116,10 @@ u8 *bitcoin_redeem_2of2(const tal_t *ctx,
} }
/* tal_count() gives the length of the script. */ /* tal_count() gives the length of the script. */
u8 *bitcoin_redeem_single(const tal_t *ctx, const u8 *key, size_t keylen) u8 *bitcoin_redeem_single(const tal_t *ctx, const struct pubkey *key)
{ {
u8 *script = tal_arr(ctx, u8, 0); u8 *script = tal_arr(ctx, u8, 0);
add_push_bytes(&script, key, keylen); add_push_key(&script, key);
add_op(&script, OP_CHECKSIG); add_op(&script, OP_CHECKSIG);
return script; return script;
} }
@ -193,9 +188,9 @@ bool is_pay_to_pubkey_hash(const ProtobufCBinaryData *script)
* mysig and relative locktime passed, OR * mysig and relative locktime passed, OR
* theirsig and hash preimage. */ * theirsig and hash preimage. */
u8 *bitcoin_redeem_revocable(const tal_t *ctx, u8 *bitcoin_redeem_revocable(const tal_t *ctx,
const BitcoinPubkey *mykey, const struct pubkey *mykey,
u32 locktime, u32 locktime,
const BitcoinPubkey *theirkey, const struct pubkey *theirkey,
const Sha256Hash *revocation_hash) const Sha256Hash *revocation_hash)
{ {
u8 *script = tal_arr(ctx, u8, 0); u8 *script = tal_arr(ctx, u8, 0);
@ -221,7 +216,7 @@ u8 *bitcoin_redeem_revocable(const tal_t *ctx,
add_op(&script, OP_HASH160); add_op(&script, OP_HASH160);
add_push_bytes(&script, rhash_ripemd, sizeof(rhash_ripemd)); add_push_bytes(&script, rhash_ripemd, sizeof(rhash_ripemd));
add_op(&script, OP_EQUALVERIFY); add_op(&script, OP_EQUALVERIFY);
add_push_bytes(&script, theirkey->key.data, theirkey->key.len); add_push_key(&script, theirkey);
add_op(&script, OP_CHECKSIG); add_op(&script, OP_CHECKSIG);
/* Otherwise, it should be both our sigs. */ /* Otherwise, it should be both our sigs. */
@ -236,11 +231,11 @@ u8 *bitcoin_redeem_revocable(const tal_t *ctx,
add_op(&script, OP_LITERAL(2)); add_op(&script, OP_LITERAL(2));
/* This obscures whose key is whose. Probably unnecessary? */ /* This obscures whose key is whose. Probably unnecessary? */
if (key_less(mykey, theirkey)) { if (key_less(mykey, theirkey)) {
add_push_bytes(&script, mykey->key.data, mykey->key.len); add_push_key(&script, mykey);
add_push_bytes(&script, theirkey->key.data, theirkey->key.len); add_push_key(&script, theirkey);
} else { } else {
add_push_bytes(&script, theirkey->key.data, theirkey->key.len); add_push_key(&script, theirkey);
add_push_bytes(&script, mykey->key.data, mykey->key.len); add_push_key(&script, mykey);
} }
add_op(&script, OP_LITERAL(2)); add_op(&script, OP_LITERAL(2));
add_op(&script, OP_CHECKMULTISIG); add_op(&script, OP_CHECKMULTISIG);
@ -250,7 +245,7 @@ u8 *bitcoin_redeem_revocable(const tal_t *ctx,
add_op(&script, OP_ELSE); add_op(&script, OP_ELSE);
add_push_bytes(&script, &locktime_le, sizeof(locktime_le)); add_push_bytes(&script, &locktime_le, sizeof(locktime_le));
add_op(&script, OP_CHECKSEQUENCEVERIFY); add_op(&script, OP_CHECKSEQUENCEVERIFY);
add_push_bytes(&script, mykey->key.data, mykey->key.len); add_push_key(&script, mykey);
add_op(&script, OP_CHECKSIG); add_op(&script, OP_CHECKSIG);
add_op(&script, OP_ENDIF); add_op(&script, OP_ENDIF);

12
bitcoin_script.h

@ -5,25 +5,25 @@
#include "lightning.pb-c.h" #include "lightning.pb-c.h"
struct bitcoin_address; struct bitcoin_address;
struct bitcoin_compressed_pubkey; struct pubkey;
struct signature; struct signature;
/* tal_count() gives the length of the script. */ /* tal_count() gives the length of the script. */
u8 *bitcoin_redeem_2of2(const tal_t *ctx, u8 *bitcoin_redeem_2of2(const tal_t *ctx,
const BitcoinPubkey *key1, const struct pubkey *key1,
const BitcoinPubkey *key2); const struct pubkey *key2);
/* tal_count() gives the length of the script. */ /* tal_count() gives the length of the script. */
u8 *bitcoin_redeem_single(const tal_t *ctx, const u8 *key, size_t keylen); u8 *bitcoin_redeem_single(const tal_t *ctx, const struct pubkey *key);
/* One of: /* One of:
* mysig and theirsig, OR * mysig and theirsig, OR
* mysig and relative locktime passed, OR * mysig and relative locktime passed, OR
* theirsig and hash preimage. */ * theirsig and hash preimage. */
u8 *bitcoin_redeem_revocable(const tal_t *ctx, u8 *bitcoin_redeem_revocable(const tal_t *ctx,
const BitcoinPubkey *mykey, const struct pubkey *mykey,
u32 locktime, u32 locktime,
const BitcoinPubkey *theirkey, const struct pubkey *theirkey,
const Sha256Hash *revocation_hash); const Sha256Hash *revocation_hash);
/* Create an output script using p2sh for this redeem script. */ /* Create an output script using p2sh for this redeem script. */

11
commit_tx.c

@ -3,6 +3,7 @@
#include "bitcoin_tx.h" #include "bitcoin_tx.h"
#include "bitcoin_script.h" #include "bitcoin_script.h"
#include "permute_tx.h" #include "permute_tx.h"
#include "pubkey.h"
struct bitcoin_tx *create_commit_tx(const tal_t *ctx, struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
OpenChannel *ours, OpenChannel *ours,
@ -12,6 +13,7 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
{ {
struct bitcoin_tx *tx; struct bitcoin_tx *tx;
const u8 *redeemscript; const u8 *redeemscript;
struct pubkey ourkey, theirkey;
/* Now create commitment tx: one input, two outputs. */ /* Now create commitment tx: one input, two outputs. */
tx = bitcoin_tx(ctx, 1, 2); tx = bitcoin_tx(ctx, 1, 2);
@ -20,10 +22,15 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
tx->input[0].txid = *anchor_txid; tx->input[0].txid = *anchor_txid;
tx->input[0].index = anchor_output; tx->input[0].index = anchor_output;
if (!proto_to_pubkey(ours->anchor->pubkey, &ourkey))
return tal_free(tx);
if (!proto_to_pubkey(theirs->anchor->pubkey, &theirkey))
return tal_free(tx);
/* First output is a P2SH to a complex redeem script (usu. for me) */ /* First output is a P2SH to a complex redeem script (usu. for me) */
redeemscript = bitcoin_redeem_revocable(tx, ours->anchor->pubkey, redeemscript = bitcoin_redeem_revocable(tx, &ourkey,
ours->locktime_seconds, ours->locktime_seconds,
theirs->anchor->pubkey, &theirkey,
ours->revocation_hash); ours->revocation_hash);
tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript); tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript);
tx->output[0].script_length = tal_count(tx->output[0].script); tx->output[0].script_length = tal_count(tx->output[0].script);

Loading…
Cancel
Save