Skip to content

Commit 64008e2

Browse files
rustyrussellcdecker
authored andcommitted
common/derive_basepoints: add routines to get a specific secret.
Often we only need a single secret, so it's clearer to have routines to do just that. When we change to the lnd key scheme, there will be no benefit in calculating them all together. This also adds a test! Signed-off-by: Rusty Russell <[email protected]>
1 parent b2b8510 commit 64008e2

File tree

3 files changed

+281
-0
lines changed

3 files changed

+281
-0
lines changed

common/derive_basepoints.c

+79
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,85 @@ bool per_commit_point(const struct sha256 *shaseed,
8787
return true;
8888
}
8989

90+
bool derive_payment_basepoint(const struct secret *seed,
91+
struct pubkey *payment_basepoint,
92+
struct secret *payment_secret)
93+
{
94+
struct keys {
95+
struct privkey f, r, h, p, d;
96+
struct sha256 shaseed;
97+
} keys;
98+
99+
hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed),
100+
"c-lightning", strlen("c-lightning"));
101+
102+
if (payment_basepoint) {
103+
if (!pubkey_from_privkey(&keys.p, payment_basepoint))
104+
return false;
105+
}
106+
107+
if (payment_secret)
108+
*payment_secret = keys.p.secret;
109+
110+
return true;
111+
}
112+
113+
bool derive_delayed_payment_basepoint(const struct secret *seed,
114+
struct pubkey *delayed_payment_basepoint,
115+
struct secret *delayed_payment_secret)
116+
{
117+
struct keys {
118+
struct privkey f, r, h, p, d;
119+
struct sha256 shaseed;
120+
} keys;
121+
122+
hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed),
123+
"c-lightning", strlen("c-lightning"));
124+
125+
if (delayed_payment_basepoint) {
126+
if (!pubkey_from_privkey(&keys.d, delayed_payment_basepoint))
127+
return false;
128+
}
129+
130+
if (delayed_payment_secret)
131+
*delayed_payment_secret = keys.d.secret;
132+
133+
return true;
134+
}
135+
136+
bool derive_shaseed(const struct secret *seed, struct sha256 *shaseed)
137+
{
138+
struct keys {
139+
struct privkey f, r, h, p, d;
140+
struct sha256 shaseed;
141+
} keys;
142+
143+
hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed),
144+
"c-lightning", strlen("c-lightning"));
145+
*shaseed = keys.shaseed;
146+
return true;
147+
}
148+
149+
bool derive_funding_key(const struct secret *seed,
150+
struct pubkey *funding_pubkey,
151+
struct privkey *funding_privkey)
152+
{
153+
struct privkey f;
154+
155+
hkdf_sha256(&f, sizeof(f), NULL, 0, seed, sizeof(*seed),
156+
"c-lightning", strlen("c-lightning"));
157+
158+
if (funding_pubkey) {
159+
if (!pubkey_from_privkey(&f, funding_pubkey))
160+
return false;
161+
}
162+
163+
if (funding_privkey)
164+
*funding_privkey = f;
165+
166+
return true;
167+
}
168+
90169
void towire_basepoints(u8 **pptr, const struct basepoints *b)
91170
{
92171
towire_pubkey(pptr, &b->revocation);

common/derive_basepoints.h

+45
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,51 @@ bool derive_basepoints(const struct secret *seed,
3838
struct secrets *secrets,
3939
struct sha256 *shaseed);
4040

41+
/**
42+
* derive_funding_key - give a (per-peer) seed, get just funding key
43+
* @seed: (in) seed (derived by master daemon from counter and main seed)
44+
* @funding_pubkey: (out) pubkey for funding tx output (if non-NULL)
45+
* @funding_privkey: (out) privkey for funding tx output (if non-NULL)
46+
*
47+
* This is a cut-down version of derive_basepoints.
48+
*/
49+
bool derive_funding_key(const struct secret *seed,
50+
struct pubkey *funding_pubkey,
51+
struct privkey *funding_privkey);
52+
53+
/**
54+
* derive_payment_basepoint - give a (per-channel) seed, get just payment basepoint
55+
* @seed: (in) seed (derived by master daemon from counter and main seed)
56+
* @payment_basepoint: (out) basepoint for payment output (if non-NULL)
57+
* @payment_secret: (out) secret for payment basepoint (if non-NULL)
58+
*
59+
* This is a cut-down version of derive_basepoints.
60+
*/
61+
bool derive_payment_basepoint(const struct secret *seed,
62+
struct pubkey *payment_basepoint,
63+
struct secret *payment_secret);
64+
65+
/**
66+
* derive_shaseed - give a (per-peer) seed, get just the shaseed
67+
* @seed: (in) seed (derived by master daemon from counter and main seed)
68+
* @shaseed: (out) seed for shachain
69+
*
70+
* This is a cut-down version of derive_basepoints.
71+
*/
72+
bool derive_shaseed(const struct secret *seed, struct sha256 *shaseed);
73+
74+
/**
75+
* derive_delayed_payment_basepoint - give a (per-channel) seed, get just delayed payment basepoint
76+
* @seed: (in) seed (derived by master daemon from counter and main seed)
77+
* @delayed_payment_basepoint: (out) basepoint for payment output (if non-NULL)
78+
* @delayed_payment_secret: (out) secret for payment basepoint (if non-NULL)
79+
*
80+
* This is a cut-down version of derive_basepoints.
81+
*/
82+
bool derive_delayed_payment_basepoint(const struct secret *seed,
83+
struct pubkey *delayed_payment_basepoint,
84+
struct secret *delayed_payment_secret);
85+
4186
/**
4287
* per_commit_secret - get a secret for this index.
4388
* @shaseed: the sha256 seed

common/test/run-derive_basepoints.c

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#include "../derive_basepoints.c"
2+
#include <ccan/err/err.h>
3+
#include <ccan/mem/mem.h>
4+
#include <ccan/str/hex/hex.h>
5+
#include <ccan/structeq/structeq.h>
6+
#include <common/utils.h>
7+
#include <stdio.h>
8+
#include <wally_core.h>
9+
10+
/* AUTOGENERATED MOCKS START */
11+
/* Generated stub for fromwire_pubkey */
12+
void fromwire_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct pubkey *pubkey UNNEEDED)
13+
{ fprintf(stderr, "fromwire_pubkey called!\n"); abort(); }
14+
/* Generated stub for towire_pubkey */
15+
void towire_pubkey(u8 **pptr UNNEEDED, const struct pubkey *pubkey UNNEEDED)
16+
{ fprintf(stderr, "towire_pubkey called!\n"); abort(); }
17+
/* AUTOGENERATED MOCKS END */
18+
19+
STRUCTEQ_DEF(basepoints, 0,
20+
revocation.pubkey,
21+
payment.pubkey,
22+
htlc.pubkey,
23+
delayed_payment.pubkey);
24+
STRUCTEQ_DEF(secrets, 0,
25+
funding_privkey.secret.data,
26+
revocation_basepoint_secret.data,
27+
payment_basepoint_secret.data,
28+
htlc_basepoint_secret.data,
29+
delayed_payment_basepoint_secret.data);
30+
STRUCTEQ_DEF(privkey, 0,
31+
secret.data);
32+
33+
struct info {
34+
struct secret seed;
35+
struct pubkey funding_pubkey;
36+
struct basepoints basepoints;
37+
struct secrets secrets;
38+
struct sha256 shaseed;
39+
};
40+
41+
/* We get a fresh one each time, to catch uninitialized fields */
42+
static struct info *new_info(const tal_t *ctx)
43+
{
44+
struct info *info = tal(ctx, struct info);
45+
memset(&info->seed, 7, sizeof(info->seed));
46+
47+
return info;
48+
}
49+
50+
int main(void)
51+
{
52+
setup_locale();
53+
54+
const tal_t *ctx = tal(NULL, char);
55+
struct info *baseline, *info;
56+
57+
secp256k1_ctx = wally_get_secp_context();
58+
baseline = new_info(ctx);
59+
assert(derive_basepoints(&baseline->seed, &baseline->funding_pubkey,
60+
&baseline->basepoints,
61+
&baseline->secrets,
62+
&baseline->shaseed));
63+
64+
/* Same seed, same result. */
65+
info = new_info(ctx);
66+
assert(derive_basepoints(&info->seed, &info->funding_pubkey,
67+
&info->basepoints,
68+
&info->secrets,
69+
&info->shaseed));
70+
assert(pubkey_eq(&baseline->funding_pubkey, &info->funding_pubkey));
71+
assert(basepoints_eq(&baseline->basepoints, &info->basepoints));
72+
assert(secrets_eq(&baseline->secrets, &info->secrets));
73+
assert(sha256_eq(&baseline->shaseed, &info->shaseed));
74+
75+
/* Different seed, different result. */
76+
for (size_t i = 0; i < sizeof(info->seed); i++) {
77+
for (size_t b = 0; b < CHAR_BIT; b++) {
78+
info = new_info(ctx);
79+
info->seed.data[i] ^= (1 << b);
80+
81+
assert(derive_basepoints(&info->seed,
82+
&info->funding_pubkey,
83+
&info->basepoints,
84+
&info->secrets,
85+
&info->shaseed));
86+
assert(!pubkey_eq(&baseline->funding_pubkey,
87+
&info->funding_pubkey));
88+
assert(!basepoints_eq(&baseline->basepoints,
89+
&info->basepoints));
90+
assert(!secrets_eq(&baseline->secrets, &info->secrets));
91+
assert(!sha256_eq(&baseline->shaseed, &info->shaseed));
92+
}
93+
}
94+
95+
/* Any field can be NULL (except seed). */
96+
info = new_info(ctx);
97+
assert(derive_basepoints(&info->seed, NULL,
98+
&info->basepoints,
99+
&info->secrets,
100+
&info->shaseed));
101+
assert(basepoints_eq(&baseline->basepoints, &info->basepoints));
102+
assert(secrets_eq(&baseline->secrets, &info->secrets));
103+
assert(sha256_eq(&baseline->shaseed, &info->shaseed));
104+
105+
info = new_info(ctx);
106+
assert(derive_basepoints(&info->seed, &info->funding_pubkey,
107+
NULL,
108+
&info->secrets,
109+
&info->shaseed));
110+
assert(pubkey_eq(&baseline->funding_pubkey, &info->funding_pubkey));
111+
assert(secrets_eq(&baseline->secrets, &info->secrets));
112+
assert(sha256_eq(&baseline->shaseed, &info->shaseed));
113+
114+
info = new_info(ctx);
115+
assert(derive_basepoints(&info->seed, &info->funding_pubkey,
116+
&info->basepoints,
117+
NULL,
118+
&info->shaseed));
119+
assert(pubkey_eq(&baseline->funding_pubkey, &info->funding_pubkey));
120+
assert(basepoints_eq(&baseline->basepoints, &info->basepoints));
121+
assert(sha256_eq(&baseline->shaseed, &info->shaseed));
122+
123+
info = new_info(ctx);
124+
assert(derive_basepoints(&info->seed, &info->funding_pubkey,
125+
&info->basepoints,
126+
&info->secrets,
127+
NULL));
128+
assert(pubkey_eq(&baseline->funding_pubkey, &info->funding_pubkey));
129+
assert(basepoints_eq(&baseline->basepoints, &info->basepoints));
130+
assert(secrets_eq(&baseline->secrets, &info->secrets));
131+
132+
/* derive_payment_basepoint should give same results. */
133+
info = new_info(ctx);
134+
assert(derive_payment_basepoint(&info->seed, &info->basepoints.payment,
135+
&info->secrets.payment_basepoint_secret));
136+
assert(pubkey_eq(&baseline->basepoints.payment,
137+
&info->basepoints.payment));
138+
assert(secret_eq(&baseline->secrets.payment_basepoint_secret,
139+
&info->secrets.payment_basepoint_secret));
140+
141+
/* derive_funding_key should give same results. */
142+
info = new_info(ctx);
143+
assert(derive_funding_key(&info->seed, &info->funding_pubkey,
144+
&info->secrets.funding_privkey));
145+
assert(pubkey_eq(&baseline->funding_pubkey, &info->funding_pubkey));
146+
assert(privkey_eq(&baseline->secrets.funding_privkey,
147+
&info->secrets.funding_privkey));
148+
149+
/* derive_shaseed should give same results. */
150+
info = new_info(ctx);
151+
assert(derive_shaseed(&info->seed, &info->shaseed));
152+
assert(sha256_eq(&baseline->shaseed, &info->shaseed));
153+
154+
tal_free(ctx);
155+
wally_cleanup(0);
156+
return 0;
157+
}

0 commit comments

Comments
 (0)