rgb-cln/lightningd/key_derive.c

259 lines
8.5 KiB
C

#include <bitcoin/privkey.h>
#include <bitcoin/pubkey.h>
#include <ccan/crypto/sha256/sha256.h>
#include <lightningd/key_derive.h>
#include <utils.h>
#include <wally_bip32.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;
}
bool bip32_pubkey(const struct ext_key *bip32_base,
struct pubkey *pubkey, u32 index)
{
struct ext_key ext;
if (index >= BIP32_INITIAL_HARDENED_CHILD)
return false;
if (bip32_key_from_parent(bip32_base, index,
BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK)
return false;
if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey->pubkey,
ext.pub_key, sizeof(ext.pub_key)))
return false;
return true;
}