/* 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_privkey_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; }
static void log_to_file(const char *prefix, enum log_level level, bool continued, const struct timeabs *time, const char *str, const u8 *io, size_t io_len, FILE *logf) { char iso8601_msec_fmt[sizeof("YYYY-mm-ddTHH:MM:SS.%03dZ")]; strftime(iso8601_msec_fmt, sizeof(iso8601_msec_fmt), "%FT%T.%%03dZ", gmtime(&time->ts.tv_sec)); char iso8601_s[sizeof("YYYY-mm-ddTHH:MM:SS.nnnZ")]; snprintf(iso8601_s, sizeof(iso8601_s), iso8601_msec_fmt, (int) time->ts.tv_nsec / 1000000); if (level == LOG_IO_IN || level == LOG_IO_OUT) { const char *dir = level == LOG_IO_IN ? "[IN]" : "[OUT]"; char *hex = tal_hexstr(NULL, io, io_len); fprintf(logf, "%s %s%s%s %s\n", iso8601_s, prefix, str, dir, hex); tal_free(hex); } else if (!continued) { fprintf(logf, "%s %s %s\n", iso8601_s, prefix, str); } else { fprintf(logf, "%s %s \t%s\n", iso8601_s, prefix, str); } fflush(logf); }
static void hexeq(const void *p, size_t len, const char *hex) { char *tmphex = tal_hexstr(NULL, p, len); if (strcmp(hex, tmphex)) { fprintf(stderr, "Expected '%s' got '%s'", hex, tmphex); abort(); } tal_free(tmphex); }
char *netaddr_to_hex(const tal_t *ctx, const struct netaddr *a) { u8 *blob = tal_arr(ctx, u8, 0); char *hex; push_le32(a->type, push, &blob); push_le32(a->protocol, push, &blob); push_le32(a->addrlen, push, &blob); assert(a->addrlen <= sizeof(a->saddr)); push(&a->saddr, a->addrlen, &blob); hex = tal_hexstr(ctx, blob, tal_count(blob)); tal_free(blob); return hex; }
/* 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_privkey_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_privkey_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_privkey_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; }
/* 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", type_to_string(tmpctx, secp256k1_pubkey, &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", 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; }
char *tal_hex(const tal_t *ctx, const tal_t *data) { return tal_hexstr(ctx, data, tal_bytelen(data)); }
int main(void) { setup_locale(); struct privkey privkey; struct secret base_secret, per_commitment_secret; struct pubkey base_point, per_commitment_point, pubkey, pubkey2; setup_tmpctx(); secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); base_secret = secret_from_hex("0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); per_commitment_secret = secret_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 (!secp256k1_ec_pubkey_create(secp256k1_ctx, &per_commitment_point.pubkey, per_commitment_secret.data)) abort(); if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &base_point.pubkey, base_secret.data)) 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; }