Files
palladum-lightning/common/key_derive.c
Rusty Russell 6e5cb299dd global: remove unnecessary includes from C files.
Basically, `devtools/reduce-includes.sh */*.c`.

Build time from make clean (RUST=0) (includes building external libs):

Before:
	real    0m38.944000-40.416000(40.1131+/-0.4)s
	user    3m6.790000-17.159000(15.0571+/-2.8)s
	sys     0m35.304000-37.336000(36.8942+/-0.57)s
After:
	real    0m37.872000-39.974000(39.5466+/-0.59)s
	user    3m1.211000-14.968000(12.4556+/-3.9)s
	sys     0m35.008000-36.830000(36.4143+/-0.5)s

Build time after touch config.vars (RUST=0):

Before:
	real    0m19.831000-21.862000(21.5528+/-0.58)s
	user    2m15.361000-30.731000(28.4798+/-4.4)s
	sys     0m21.056000-22.339000(22.0346+/-0.35)s

After:
	real    0m18.384000-21.307000(20.8605+/-0.92)s
	user    2m5.585000-26.843000(23.6017+/-6.7)s
	sys     0m19.650000-22.003000(21.4943+/-0.69)s

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-10-23 06:44:04 +10:30

255 lines
8.9 KiB
C

#include "config.h"
#include <bitcoin/privkey.h>
#include <bitcoin/pubkey.h>
#include <common/key_derive.h>
#include <common/utils.h>
/* BOLT #3:
*
* ### `localpubkey`, `local_htlcpubkey`, `remote_htlcpubkey`, `local_delayedpubkey`, and `remote_delayedpubkey` Derivation
*
* These pubkeys are simply generated by addition from their base points:
*
* pubkey = basepoint + SHA256(per_commitment_point || basepoint) * G
*
* - The `localpubkey` uses the local node's `payment_basepoint`;
* - The `local_htlcpubkey` uses the local node's `htlc_basepoint`;
* - The `remote_htlcpubkey` uses the remote node's `htlc_basepoint`;
* - The `local_delayedpubkey` uses the local node's `delayed_payment_basepoint`;
* - The `remote_delayedpubkey` uses the remote node's `delayed_payment_basepoint`.
*...
* The `remotepubkey` is simply the remote node's `payment_basepoint`.
*/
/* The old BOLT defined what happened prior to option_static_remotekey,
* which we still support for existing channels:
*
* If `option_static_remotekey` or `option_anchors` is negotiated, the
* `remotepubkey` is simply the remote node's `payment_basepoint`, otherwise
* it is calculated as above using the remote node's `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_CMPR_LEN * 2];
pubkey_to_der(der_keys, per_commitment_point);
pubkey_to_der(der_keys + PUBKEY_CMPR_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_CMPR_LEN),
tal_hexstr(tmpctx, der_keys + PUBKEY_CMPR_LEN, PUBKEY_CMPR_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",
fmt_pubkey(tmpctx, basepoint));
printf("# = 0x%s\n",
fmt_pubkey(tmpctx, key));
#endif
return true;
}
/* BOLT #3:
*
* The corresponding private keys can be similarly derived, if the basepoint
* secrets are known (i.e. the private keys corresponding to `localpubkey`,
* `local_htlcpubkey`, and `local_delayedpubkey` only):
*
* privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)
*/
bool derive_simple_privkey(const struct secret *base_secret,
const struct pubkey *basepoint,
const struct pubkey *per_commitment_point,
struct privkey *key)
{
struct sha256 sha;
unsigned char der_keys[PUBKEY_CMPR_LEN * 2];
pubkey_to_der(der_keys, per_commitment_point);
pubkey_to_der(der_keys + PUBKEY_CMPR_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_CMPR_LEN),
tal_hexstr(tmpctx, der_keys + PUBKEY_CMPR_LEN, PUBKEY_CMPR_LEN));
printf("# = 0x%s\n", tal_hexstr(tmpctx, &sha, sizeof(sha)));
#endif
key->secret = *base_secret;
if (secp256k1_ec_seckey_tweak_add(secp256k1_ctx, key->secret.data,
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 `revocationpubkey` is a blinded key: when the local node wishes to
* create a new commitment for the remote node, it uses its own
* `revocation_basepoint` and the remote node's `per_commitment_point` to
* derive a new `revocationpubkey` for the commitment. After the remote node
* reveals the `per_commitment_secret` used (thereby revoking that
* commitment), the local node can then derive the `revocationprivkey`, as it
* now knows the two secrets necessary to derive the key
* (`revocation_basepoint_secret` and `per_commitment_secret`).
*
* The `per_commitment_point` is generated using elliptic-curve multiplication:
*
* per_commitment_point = per_commitment_secret * G
*
* And this is used to derive the revocation pubkey from the remote node's
* `revocation_basepoint`:
*
* revocationpubkey = 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_CMPR_LEN * 2];
secp256k1_pubkey add[2];
const secp256k1_pubkey *args[2];
pubkey_to_der(der_keys, basepoint);
pubkey_to_der(der_keys + PUBKEY_CMPR_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_CMPR_LEN),
tal_hexstr(tmpctx, der_keys + PUBKEY_CMPR_LEN, PUBKEY_CMPR_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",
fmt_secp256k1_pubkey(tmpctx, &add[0]));
#endif
pubkey_to_der(der_keys, per_commitment_point);
pubkey_to_der(der_keys + PUBKEY_CMPR_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_CMPR_LEN),
tal_hexstr(tmpctx, der_keys + PUBKEY_CMPR_LEN, PUBKEY_CMPR_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",
fmt_secp256k1_pubkey(tmpctx, &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",
fmt_secp256k1_pubkey(tmpctx, args[0]),
fmt_secp256k1_pubkey(tmpctx, args[1]),
fmt_pubkey(tmpctx, key));
#endif
return true;
}
/* BOLT #3:
*
* The corresponding private key can be derived once the `per_commitment_secret`
* is known:
*
* revocationprivkey = revocation_basepoint_secret * SHA256(revocation_basepoint || per_commitment_point) + per_commitment_secret * SHA256(per_commitment_point || revocation_basepoint)
*/
bool derive_revocation_privkey(const struct secret *base_secret,
const struct secret *per_commitment_secret,
const struct pubkey *basepoint,
const struct pubkey *per_commitment_point,
struct privkey *key)
{
struct sha256 sha;
unsigned char der_keys[PUBKEY_CMPR_LEN * 2];
struct secret part2;
pubkey_to_der(der_keys, basepoint);
pubkey_to_der(der_keys + PUBKEY_CMPR_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_CMPR_LEN),
tal_hexstr(tmpctx, der_keys + PUBKEY_CMPR_LEN, PUBKEY_CMPR_LEN));
printf("# = 0x%s\n", tal_hexstr(tmpctx, sha.u.u8, sizeof(sha.u.u8))),
#endif
key->secret = *base_secret;
if (secp256k1_ec_seckey_tweak_mul(secp256k1_ctx, key->secret.data,
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_CMPR_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_CMPR_LEN),
tal_hexstr(tmpctx, der_keys + PUBKEY_CMPR_LEN, PUBKEY_CMPR_LEN));
printf("# = 0x%s\n", tal_hexstr(tmpctx, sha.u.u8, sizeof(sha.u.u8))),
#endif
part2 = *per_commitment_secret;
if (secp256k1_ec_seckey_tweak_mul(secp256k1_ctx, part2.data,
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_seckey_tweak_add(secp256k1_ctx, key->secret.data,
part2.data) != 1)
return false;
#ifdef SUPERVERBOSE
printf("# => 0x%s\n", tal_hexstr(tmpctx, key, sizeof(*key)));
#endif
return true;
}