1 // This file is Copyright its original authors, visible in version control
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
10 //! Keys used to generate commitment transactions.
11 //! See: <https://github.com/lightning/bolts/blob/master/03-transactions.md#keys>
14 use crate::ln::msgs::DecodeError;
15 use crate::util::ser::Readable;
16 use crate::util::ser::Writeable;
17 use crate::util::ser::Writer;
18 use bitcoin::hashes::sha256::Hash as Sha256;
19 use bitcoin::hashes::Hash;
20 use bitcoin::hashes::HashEngine;
21 use bitcoin::secp256k1;
22 use bitcoin::secp256k1::PublicKey;
23 use bitcoin::secp256k1::Scalar;
24 use bitcoin::secp256k1::Secp256k1;
25 use bitcoin::secp256k1::SecretKey;
27 macro_rules! doc_comment {
28 ($x:expr, $($tt:tt)*) => {
33 macro_rules! basepoint_impl {
36 /// Get inner Public Key
37 pub fn to_public_key(&self) -> PublicKey {
41 /// Derives a per-commitment-transaction (eg an htlc key or delayed_payment key) private key addition tweak
42 /// from a basepoint and a per_commitment_point:
43 /// `privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)`
44 /// This calculates the hash part in the tweak derivation process, which is used to ensure
45 /// that each key is unique and cannot be guessed by an external party. It is equivalent
46 /// to the `from_basepoint` method, but without the addition operation, providing just the
47 /// tweak from the hash of the per_commitment_point and the basepoint.
48 pub fn derive_add_tweak(&self, per_commitment_point: &PublicKey) -> [u8; 32] {
49 let mut sha = Sha256::engine();
50 sha.input(&per_commitment_point.serialize());
51 sha.input(&self.to_public_key().serialize());
52 Sha256::from_engine(sha).to_byte_array()
56 impl From<PublicKey> for $BasepointT {
57 fn from(value: PublicKey) -> Self {
63 macro_rules! key_impl {
64 ($BasepointT:ty, $KeyName:expr) => {
66 concat!("Derive a public ", $KeyName, " using one node's `per_commitment_point` and its countersignatory's `basepoint`"),
67 pub fn from_basepoint<T: secp256k1::Signing>(
68 secp_ctx: &Secp256k1<T>,
69 countersignatory_basepoint: &$BasepointT,
70 per_commitment_point: &PublicKey,
72 Self(derive_public_key(secp_ctx, per_commitment_point, &countersignatory_basepoint.0))
77 concat!("Build a ", $KeyName, " directly from an already-derived private key"),
78 pub fn from_secret_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, sk: &SecretKey) -> Self {
79 Self(PublicKey::from_secret_key(&secp_ctx, &sk))
83 /// Get inner Public Key
84 pub fn to_public_key(&self) -> PublicKey {
89 macro_rules! key_read_write {
91 impl Writeable for $SelfT {
92 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
93 self.0.serialize().write(w)
97 impl Readable for $SelfT {
98 fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
99 let key: PublicKey = Readable::read(r)?;
106 /// Base key used in conjunction with a `per_commitment_point` to generate a [`DelayedPaymentKey`].
108 /// The delayed payment key is used to pay the commitment state broadcaster their
109 /// non-HTLC-encumbered funds after a delay to give their counterparty a chance to punish if the
110 /// state broadcasted was previously revoked.
111 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
112 pub struct DelayedPaymentBasepoint(pub PublicKey);
113 basepoint_impl!(DelayedPaymentBasepoint);
114 key_read_write!(DelayedPaymentBasepoint);
116 /// A derived key built from a [`DelayedPaymentBasepoint`] and `per_commitment_point`.
118 /// The delayed payment key is used to pay the commitment state broadcaster their
119 /// non-HTLC-encumbered funds after a delay. This delay gives their counterparty a chance to
120 /// punish and claim all the channel funds if the state broadcasted was previously revoked.
122 /// [See the BOLT specs]
123 /// (https://github.com/lightning/bolts/blob/master/03-transactions.md#localpubkey-local_htlcpubkey-remote_htlcpubkey-local_delayedpubkey-and-remote_delayedpubkey-derivation)
124 /// for more information on key derivation details.
125 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
126 pub struct DelayedPaymentKey(pub PublicKey);
128 impl DelayedPaymentKey {
129 key_impl!(DelayedPaymentBasepoint, "delayedpubkey");
131 key_read_write!(DelayedPaymentKey);
133 /// Base key used in conjunction with a `per_commitment_point` to generate an [`HtlcKey`].
135 /// HTLC keys are used to ensure only the recipient of an HTLC can claim it on-chain with the HTLC
136 /// preimage and that only the sender of an HTLC can claim it on-chain after it has timed out.
137 /// Thus, both channel counterparties' HTLC keys will appears in each HTLC output's script.
138 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
139 pub struct HtlcBasepoint(pub PublicKey);
140 basepoint_impl!(HtlcBasepoint);
141 key_read_write!(HtlcBasepoint);
143 /// A derived key built from a [`HtlcBasepoint`] and `per_commitment_point`.
145 /// HTLC keys are used to ensure only the recipient of an HTLC can claim it on-chain with the HTLC
146 /// preimage and that only the sender of an HTLC can claim it on-chain after it has timed out.
147 /// Thus, both channel counterparties' HTLC keys will appears in each HTLC output's script.
149 /// [See the BOLT specs]
150 /// (https://github.com/lightning/bolts/blob/master/03-transactions.md#localpubkey-local_htlcpubkey-remote_htlcpubkey-local_delayedpubkey-and-remote_delayedpubkey-derivation)
151 /// for more information on key derivation details.
152 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
153 pub struct HtlcKey(pub PublicKey);
156 key_impl!(HtlcBasepoint, "htlcpubkey");
158 key_read_write!(HtlcKey);
160 /// Derives a per-commitment-transaction public key (eg an htlc key or a delayed_payment key)
161 /// from the base point and the per_commitment_key. This is the public equivalent of
162 /// derive_private_key - using only public keys to derive a public key instead of private keys.
163 fn derive_public_key<T: secp256k1::Signing>(
164 secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_point: &PublicKey,
166 let mut sha = Sha256::engine();
167 sha.input(&per_commitment_point.serialize());
168 sha.input(&base_point.serialize());
169 let res = Sha256::from_engine(sha).to_byte_array();
171 add_public_key_tweak(secp_ctx, base_point, &res)
174 /// Adds a tweak to a public key to derive a new public key.
175 pub fn add_public_key_tweak<T: secp256k1::Signing>(
176 secp_ctx: &Secp256k1<T>, base_point: &PublicKey, tweak: &[u8; 32],
178 let hashkey = PublicKey::from_secret_key(
180 &SecretKey::from_slice(tweak)
181 .expect("Hashes should always be valid keys unless SHA-256 is broken"),
183 base_point.combine(&hashkey)
184 .expect("Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak contains the hash of the key.")
187 /// Master key used in conjunction with per_commitment_point to generate [htlcpubkey](https://github.com/lightning/bolts/blob/master/03-transactions.md#key-derivation) for the latest state of a channel.
188 /// A watcher can be given a [RevocationBasepoint] to generate per commitment [RevocationKey] to create justice transactions.
189 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
190 pub struct RevocationBasepoint(pub PublicKey);
191 basepoint_impl!(RevocationBasepoint);
192 key_read_write!(RevocationBasepoint);
194 /// The revocation key is used to allow a channel party to revoke their state - giving their
195 /// counterparty the required material to claim all of their funds if they broadcast that state.
197 /// Each commitment transaction has a revocation key based on the basepoint and
198 /// per_commitment_point which is used in both commitment and HTLC transactions.
200 /// See [the BOLT spec for derivation details]
201 /// (https://github.com/lightning/bolts/blob/master/03-transactions.md#revocationpubkey-derivation)
202 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
203 pub struct RevocationKey(pub PublicKey);
206 /// Derives a per-commitment-transaction revocation public key from one party's per-commitment
207 /// point and the other party's [`RevocationBasepoint`]. This is the public equivalent of
208 /// [`chan_utils::derive_private_revocation_key`] - using only public keys to derive a public
209 /// key instead of private keys.
211 /// Note that this is infallible iff we trust that at least one of the two input keys are randomly
212 /// generated (ie our own).
214 /// [`chan_utils::derive_private_revocation_key`]: crate::ln::chan_utils::derive_private_revocation_key
215 pub fn from_basepoint<T: secp256k1::Verification>(
216 secp_ctx: &Secp256k1<T>, countersignatory_basepoint: &RevocationBasepoint,
217 per_commitment_point: &PublicKey,
219 let rev_append_commit_hash_key = {
220 let mut sha = Sha256::engine();
221 sha.input(&countersignatory_basepoint.to_public_key().serialize());
222 sha.input(&per_commitment_point.serialize());
224 Sha256::from_engine(sha).to_byte_array()
226 let commit_append_rev_hash_key = {
227 let mut sha = Sha256::engine();
228 sha.input(&per_commitment_point.serialize());
229 sha.input(&countersignatory_basepoint.to_public_key().serialize());
231 Sha256::from_engine(sha).to_byte_array()
234 let countersignatory_contrib = countersignatory_basepoint.to_public_key().mul_tweak(&secp_ctx, &Scalar::from_be_bytes(rev_append_commit_hash_key).unwrap())
235 .expect("Multiplying a valid public key by a hash is expected to never fail per secp256k1 docs");
236 let broadcaster_contrib = (&per_commitment_point).mul_tweak(&secp_ctx, &Scalar::from_be_bytes(commit_append_rev_hash_key).unwrap())
237 .expect("Multiplying a valid public key by a hash is expected to never fail per secp256k1 docs");
238 let pk = countersignatory_contrib.combine(&broadcaster_contrib)
239 .expect("Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak commits to the key.");
243 /// Get inner Public Key
244 pub fn to_public_key(&self) -> PublicKey {
248 key_read_write!(RevocationKey);
252 use super::derive_public_key;
253 use bitcoin::hashes::hex::FromHex;
254 use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
257 fn test_key_derivation() {
258 // Test vectors from BOLT 3 Appendix E:
259 let secp_ctx = Secp256k1::new();
261 let base_secret = SecretKey::from_slice(
262 &<Vec<u8>>::from_hex(
263 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
268 let per_commitment_secret = SecretKey::from_slice(
269 &<Vec<u8>>::from_hex(
270 "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
276 let base_point = PublicKey::from_secret_key(&secp_ctx, &base_secret);
278 base_point.serialize()[..],
280 "036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2"
285 let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
287 per_commitment_point.serialize()[..],
289 "025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486"
295 derive_public_key(&secp_ctx, &per_commitment_point, &base_point).serialize()[..],
297 "0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5"