5 changed files with 348 additions and 2 deletions
@ -0,0 +1,238 @@ |
|||||
|
#include <bitcoin/privkey.h> |
||||
|
#include <bitcoin/pubkey.h> |
||||
|
#include <ccan/crypto/sha256/sha256.h> |
||||
|
#include <lightningd/key_derive.h> |
||||
|
#include <utils.h> |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* ### `localkey`, `remotekey`, `local-delayedkey` and `remote-delayedkey` Derivation |
||||
|
* |
||||
|
* These keys are simply generated by addition from their base points: |
||||
|
* |
||||
|
* pubkey = basepoint + SHA256(per-commitment-point || basepoint)*G |
||||
|
* |
||||
|
* The `localkey` uses the local node's `payment-basepoint`, `remotekey` |
||||
|
* uses the remote node's `payment-basepoint`, the `local-delayedkey` |
||||
|
* uses the local node's `delayed-payment-basepoint`, and the |
||||
|
* `remote-delayedkey` uses the remote node's |
||||
|
* `delayed-payment-basepoint`. |
||||
|
*/ |
||||
|
bool derive_simple_key(const struct pubkey *basepoint, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
struct pubkey *key) |
||||
|
{ |
||||
|
struct sha256 sha; |
||||
|
unsigned char der_keys[PUBKEY_DER_LEN * 2]; |
||||
|
|
||||
|
pubkey_to_der(der_keys, per_commitment_point); |
||||
|
pubkey_to_der(der_keys + PUBKEY_DER_LEN, basepoint); |
||||
|
sha256(&sha, der_keys, sizeof(der_keys)); |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# SHA256(per-commitment-point || basepoint)\n"); |
||||
|
printf("# => SHA256(0x%s || 0x%s)\n", |
||||
|
tal_hexstr(tmpctx, der_keys, PUBKEY_DER_LEN), |
||||
|
tal_hexstr(tmpctx, der_keys + PUBKEY_DER_LEN, PUBKEY_DER_LEN)); |
||||
|
printf("# = 0x%s\n", |
||||
|
tal_hexstr(tmpctx, &sha, sizeof(sha))); |
||||
|
#endif |
||||
|
|
||||
|
*key = *basepoint; |
||||
|
if (secp256k1_ec_pubkey_tweak_add(secp256k1_ctx, |
||||
|
&key->pubkey, sha.u.u8) != 1) |
||||
|
return false; |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# + basepoint (0x%s)\n", |
||||
|
type_to_string(tmpctx, struct pubkey, basepoint)); |
||||
|
printf("# = 0x%s\n", |
||||
|
type_to_string(tmpctx, struct pubkey, key)); |
||||
|
#endif |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* The corresponding private keys can be derived similarly if the basepoint |
||||
|
* secrets are known (i.e., `localkey` and `local-delayedkey` only): |
||||
|
* |
||||
|
* secretkey = basepoint-secret + SHA256(per-commitment-point || basepoint) |
||||
|
*/ |
||||
|
bool derive_simple_privkey(const struct privkey *base_secret, |
||||
|
const struct pubkey *basepoint, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
struct privkey *key) |
||||
|
{ |
||||
|
struct sha256 sha; |
||||
|
unsigned char der_keys[PUBKEY_DER_LEN * 2]; |
||||
|
|
||||
|
pubkey_to_der(der_keys, per_commitment_point); |
||||
|
pubkey_to_der(der_keys + PUBKEY_DER_LEN, basepoint); |
||||
|
sha256(&sha, der_keys, sizeof(der_keys)); |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# SHA256(per-commitment-point || basepoint)\n"); |
||||
|
printf("# => SHA256(0x%s || 0x%s)\n", |
||||
|
tal_hexstr(tmpctx, der_keys, PUBKEY_DER_LEN), |
||||
|
tal_hexstr(tmpctx, der_keys + PUBKEY_DER_LEN, PUBKEY_DER_LEN)); |
||||
|
printf("# = 0x%s\n", tal_hexstr(tmpctx, &sha, sizeof(sha))); |
||||
|
#endif |
||||
|
|
||||
|
*key = *base_secret; |
||||
|
if (secp256k1_ec_privkey_tweak_add(secp256k1_ctx, key->secret, |
||||
|
sha.u.u8) != 1) |
||||
|
return false; |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# + basepoint_secret (0x%s)\n", |
||||
|
tal_hexstr(tmpctx, base_secret, sizeof(*base_secret))); |
||||
|
printf("# = 0x%s\n", |
||||
|
tal_hexstr(tmpctx, key, sizeof(*key))); |
||||
|
#endif |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* The revocationkey is a blinded key: the remote node provides the base, |
||||
|
* and the local node provides the blinding factor which it later |
||||
|
* reveals, so the remote node can use the secret revocationkey for a |
||||
|
* penalty transaction. |
||||
|
* |
||||
|
* The `per-commitment-point` is generated using EC multiplication: |
||||
|
* |
||||
|
* per-commitment-point = per-commitment-secret * G |
||||
|
* |
||||
|
* And this is used to derive the revocation key from the remote node's |
||||
|
* `revocation-basepoint`: |
||||
|
* |
||||
|
* revocationkey = revocation-basepoint * SHA256(revocation-basepoint || per-commitment-point) + per-commitment-point*SHA256(per-commitment-point || revocation-basepoint) |
||||
|
*/ |
||||
|
bool derive_revocation_key(const struct pubkey *basepoint, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
struct pubkey *key) |
||||
|
{ |
||||
|
struct sha256 sha; |
||||
|
unsigned char der_keys[PUBKEY_DER_LEN * 2]; |
||||
|
secp256k1_pubkey add[2]; |
||||
|
const secp256k1_pubkey *args[2]; |
||||
|
|
||||
|
pubkey_to_der(der_keys, basepoint); |
||||
|
pubkey_to_der(der_keys + PUBKEY_DER_LEN, per_commitment_point); |
||||
|
sha256(&sha, der_keys, sizeof(der_keys)); |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# SHA256(revocation-basepoint || per-commitment-point)\n"); |
||||
|
printf("# => SHA256(0x%s || 0x%s)\n", |
||||
|
tal_hexstr(tmpctx, der_keys, PUBKEY_DER_LEN), |
||||
|
tal_hexstr(tmpctx, der_keys + PUBKEY_DER_LEN, PUBKEY_DER_LEN)); |
||||
|
printf("# = 0x%s\n", tal_hexstr(tmpctx, sha.u.u8, sizeof(sha.u.u8))), |
||||
|
#endif |
||||
|
|
||||
|
add[0] = basepoint->pubkey; |
||||
|
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx, &add[0], sha.u.u8) != 1) |
||||
|
return false; |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# x revocation-basepoint = 0x%s\n", |
||||
|
type_to_string(tmpctx, secp256k1_pubkey, &add[0])); |
||||
|
#endif |
||||
|
|
||||
|
pubkey_to_der(der_keys, per_commitment_point); |
||||
|
pubkey_to_der(der_keys + PUBKEY_DER_LEN, basepoint); |
||||
|
sha256(&sha, der_keys, sizeof(der_keys)); |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# SHA256(per-commitment-point || revocation-basepoint)\n"); |
||||
|
printf("# => SHA256(0x%s || 0x%s)\n", |
||||
|
tal_hexstr(tmpctx, der_keys, PUBKEY_DER_LEN), |
||||
|
tal_hexstr(tmpctx, der_keys + PUBKEY_DER_LEN, PUBKEY_DER_LEN)); |
||||
|
printf("# = 0x%s\n", tal_hexstr(tmpctx, sha.u.u8, sizeof(sha.u.u8))), |
||||
|
#endif |
||||
|
|
||||
|
add[1] = per_commitment_point->pubkey; |
||||
|
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx, &add[1], sha.u.u8) != 1) |
||||
|
return false; |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# x per-commitment-point = 0x%s\n", |
||||
|
type_to_string(tmpctx, secp256k1_pubkey, &add[1])); |
||||
|
#endif |
||||
|
|
||||
|
args[0] = &add[0]; |
||||
|
args[1] = &add[1]; |
||||
|
if (secp256k1_ec_pubkey_combine(secp256k1_ctx, &key->pubkey, args, 2) |
||||
|
!= 1) |
||||
|
return false; |
||||
|
|
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# 0x%s + 0x%s => 0x%s\n", |
||||
|
type_to_string(tmpctx, secp256k1_pubkey, args[0]), |
||||
|
type_to_string(tmpctx, secp256k1_pubkey, args[1]), |
||||
|
type_to_string(tmpctx, struct pubkey, key)); |
||||
|
#endif |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* The corresponding private key can be derived once the `per-commitment-secret` |
||||
|
* is known: |
||||
|
* |
||||
|
* revocationsecretkey = revocation-basepoint-secret * SHA256(revocation-basepoint || per-commitment-point) + per-commitment-secret*SHA256(per-commitment-point || revocation-basepoint) |
||||
|
*/ |
||||
|
bool derive_revocation_privkey(const struct privkey *base_secret, |
||||
|
const struct privkey *per_commitment_secret, |
||||
|
const struct pubkey *basepoint, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
struct privkey *key) |
||||
|
{ |
||||
|
struct sha256 sha; |
||||
|
unsigned char der_keys[PUBKEY_DER_LEN * 2]; |
||||
|
struct privkey part2; |
||||
|
|
||||
|
pubkey_to_der(der_keys, basepoint); |
||||
|
pubkey_to_der(der_keys + PUBKEY_DER_LEN, per_commitment_point); |
||||
|
sha256(&sha, der_keys, sizeof(der_keys)); |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# SHA256(revocation-basepoint || per-commitment-point)\n"); |
||||
|
printf("# => SHA256(0x%s || 0x%s)\n", |
||||
|
tal_hexstr(tmpctx, der_keys, PUBKEY_DER_LEN), |
||||
|
tal_hexstr(tmpctx, der_keys + PUBKEY_DER_LEN, PUBKEY_DER_LEN)); |
||||
|
printf("# = 0x%s\n", tal_hexstr(tmpctx, sha.u.u8, sizeof(sha.u.u8))), |
||||
|
#endif |
||||
|
|
||||
|
*key = *base_secret; |
||||
|
if (secp256k1_ec_privkey_tweak_mul(secp256k1_ctx, key->secret, sha.u.u8) |
||||
|
!= 1) |
||||
|
return false; |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# * revocation-basepoint-secret (0x%s)", |
||||
|
tal_hexstr(tmpctx, base_secret, sizeof(*base_secret))), |
||||
|
printf("# = 0x%s\n", tal_hexstr(tmpctx, key, sizeof(*key))), |
||||
|
#endif |
||||
|
|
||||
|
pubkey_to_der(der_keys, per_commitment_point); |
||||
|
pubkey_to_der(der_keys + PUBKEY_DER_LEN, basepoint); |
||||
|
sha256(&sha, der_keys, sizeof(der_keys)); |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# SHA256(per-commitment-point || revocation-basepoint)\n"); |
||||
|
printf("# => SHA256(0x%s || 0x%s)\n", |
||||
|
tal_hexstr(tmpctx, der_keys, PUBKEY_DER_LEN), |
||||
|
tal_hexstr(tmpctx, der_keys + PUBKEY_DER_LEN, PUBKEY_DER_LEN)); |
||||
|
printf("# = 0x%s\n", tal_hexstr(tmpctx, sha.u.u8, sizeof(sha.u.u8))), |
||||
|
#endif |
||||
|
|
||||
|
part2 = *per_commitment_secret; |
||||
|
if (secp256k1_ec_privkey_tweak_mul(secp256k1_ctx, part2.secret, |
||||
|
sha.u.u8) != 1) |
||||
|
return false; |
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# * per-commitment-secret (0x%s)", |
||||
|
tal_hexstr(tmpctx, per_commitment_secret, |
||||
|
sizeof(*per_commitment_secret))), |
||||
|
printf("# = 0x%s\n", tal_hexstr(tmpctx, &part2, sizeof(part2))); |
||||
|
#endif |
||||
|
|
||||
|
if (secp256k1_ec_privkey_tweak_add(secp256k1_ctx, key->secret, |
||||
|
part2.secret) != 1) |
||||
|
return false; |
||||
|
|
||||
|
#ifdef SUPERVERBOSE |
||||
|
printf("# => 0x%s\n", tal_hexstr(tmpctx, key, sizeof(*key))); |
||||
|
#endif |
||||
|
return true; |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
#ifndef LIGHTNING_LIGHTNINGD_KEY_DERIVE_H |
||||
|
#define LIGHTNING_LIGHTNINGD_KEY_DERIVE_H |
||||
|
#include "config.h" |
||||
|
|
||||
|
struct pubkey; |
||||
|
|
||||
|
/* For `localkey`, `remotekey`, `local-delayedkey` and `remote-delayedkey` */ |
||||
|
bool derive_simple_key(const struct pubkey *basepoint, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
struct pubkey *key); |
||||
|
|
||||
|
bool derive_simple_privkey(const struct privkey *base_secret, |
||||
|
const struct pubkey *basepoint, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
struct privkey *key); |
||||
|
|
||||
|
/* For `revocationkey` */ |
||||
|
bool derive_revocation_key(const struct pubkey *basepoint, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
struct pubkey *key); |
||||
|
|
||||
|
bool derive_revocation_privkey(const struct privkey *base_secret, |
||||
|
const struct privkey *per_commitment_secret, |
||||
|
const struct pubkey *basepoint, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
struct privkey *key); |
||||
|
|
||||
|
#endif /* LIGHTNING_LIGHTNINGD_KEY_DERIVE_H */ |
@ -0,0 +1,79 @@ |
|||||
|
#define SUPERVERBOSE |
||||
|
static void *tmpctx; |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <utils.h> |
||||
|
#include <type_to_string.h> |
||||
|
#include "../key_derive.c" |
||||
|
#include <assert.h> |
||||
|
#include <ccan/str/hex/hex.h> |
||||
|
#include <stdio.h> |
||||
|
#include <type_to_string.h> |
||||
|
|
||||
|
static struct privkey privkey_from_hex(const char *hex) |
||||
|
{ |
||||
|
struct privkey privkey; |
||||
|
hex += 2; |
||||
|
if (!hex_decode(hex, strlen(hex), &privkey, sizeof(privkey))) |
||||
|
abort(); |
||||
|
return privkey; |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
struct privkey base_secret, per_commitment_secret, privkey; |
||||
|
struct pubkey base_point, per_commitment_point, pubkey, pubkey2; |
||||
|
|
||||
|
tmpctx = tal_tmpctx(NULL); |
||||
|
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY |
||||
|
| SECP256K1_CONTEXT_SIGN); |
||||
|
|
||||
|
base_secret = privkey_from_hex("0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); |
||||
|
per_commitment_secret = privkey_from_hex("0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"); |
||||
|
|
||||
|
printf("base_secret: 0x%s\n", |
||||
|
tal_hexstr(tmpctx, &base_secret, sizeof(base_secret))); |
||||
|
printf("per_commitment_secret: 0x%s\n", |
||||
|
tal_hexstr(tmpctx, &per_commitment_secret, |
||||
|
sizeof(per_commitment_secret))); |
||||
|
if (!pubkey_from_privkey(&per_commitment_secret, &per_commitment_point)) |
||||
|
abort(); |
||||
|
if (!pubkey_from_privkey(&base_secret, &base_point)) |
||||
|
abort(); |
||||
|
printf("base_point: 0x%s\n", |
||||
|
type_to_string(tmpctx, struct pubkey, &base_point)); |
||||
|
printf("per_commitment_point: 0x%s\n", |
||||
|
type_to_string(tmpctx, struct pubkey, &per_commitment_point)); |
||||
|
|
||||
|
/* FIXME: Annotate internal steps. */ |
||||
|
if (!derive_simple_key(&base_point, &per_commitment_point, &pubkey)) |
||||
|
abort(); |
||||
|
printf("localkey: 0x%s\n", |
||||
|
type_to_string(tmpctx, struct pubkey, &pubkey)); |
||||
|
if (!derive_simple_privkey(&base_secret, &base_point, |
||||
|
&per_commitment_point, &privkey)) |
||||
|
abort(); |
||||
|
printf("localprivkey: 0x%s\n", |
||||
|
tal_hexstr(tmpctx, &privkey, sizeof(privkey))); |
||||
|
pubkey_from_privkey(&privkey, &pubkey2); |
||||
|
assert(pubkey_eq(&pubkey, &pubkey2)); |
||||
|
|
||||
|
/* FIXME: Annotate internal steps. */ |
||||
|
if (!derive_revocation_key(&base_point, &per_commitment_point, &pubkey)) |
||||
|
abort(); |
||||
|
printf("revocationkey: 0x%s\n", |
||||
|
type_to_string(tmpctx, struct pubkey, &pubkey)); |
||||
|
if (!derive_revocation_privkey(&base_secret, &per_commitment_secret, |
||||
|
&base_point, &per_commitment_point, |
||||
|
&privkey)) |
||||
|
abort(); |
||||
|
printf("revocationprivkey: 0x%s\n", |
||||
|
tal_hexstr(tmpctx, &privkey, sizeof(privkey))); |
||||
|
pubkey_from_privkey(&privkey, &pubkey2); |
||||
|
assert(pubkey_eq(&pubkey, &pubkey2)); |
||||
|
|
||||
|
/* No memory leaks please */ |
||||
|
secp256k1_context_destroy(secp256k1_ctx); |
||||
|
tal_free(tmpctx); |
||||
|
return 0; |
||||
|
} |
Loading…
Reference in new issue