use secp256k1;
use crypto::digest::Digest;
-use crypto::hkdf::{hkdf_extract,hkdf_expand};
use ln::msgs;
use ln::msgs::{ErrorAction, HandleError, RAACommitmentOrder};
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
use chain::transaction::OutPoint;
+use chain::keysinterface::{ChannelKeys, KeysInterface};
use util::{transaction_utils,rng};
use util::ser::Writeable;
use util::sha2::Sha256;
use std::time::Instant;
use std::sync::{Arc};
-pub struct ChannelKeys {
- pub funding_key: SecretKey,
- pub revocation_base_key: SecretKey,
- pub payment_base_key: SecretKey,
- pub delayed_payment_base_key: SecretKey,
- pub htlc_base_key: SecretKey,
- pub channel_close_key: SecretKey,
- pub channel_monitor_claim_key: SecretKey,
- pub commitment_seed: [u8; 32],
-}
-
#[cfg(test)]
pub struct ChannelValueStat {
pub value_to_self_msat: u64,
pub their_max_htlc_value_in_flight_msat: u64, // outgoing
}
-impl ChannelKeys {
- pub fn new_from_seed(seed: &[u8; 32]) -> Result<ChannelKeys, secp256k1::Error> {
- let mut prk = [0; 32];
- hkdf_extract(Sha256::new(), b"rust-lightning key gen salt", seed, &mut prk);
- let secp_ctx = Secp256k1::without_caps();
-
- let mut okm = [0; 32];
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning funding key info", &mut okm);
- let funding_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning revocation base key info", &mut okm);
- let revocation_base_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning payment base key info", &mut okm);
- let payment_base_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning delayed payment base key info", &mut okm);
- let delayed_payment_base_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning htlc base key info", &mut okm);
- let htlc_base_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning channel close key info", &mut okm);
- let channel_close_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning channel monitor claim key info", &mut okm);
- let channel_monitor_claim_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning local commitment seed info", &mut okm);
-
- Ok(ChannelKeys {
- funding_key: funding_key,
- revocation_base_key: revocation_base_key,
- payment_base_key: payment_base_key,
- delayed_payment_base_key: delayed_payment_base_key,
- htlc_base_key: htlc_base_key,
- channel_close_key: channel_close_key,
- channel_monitor_claim_key: channel_monitor_claim_key,
- commitment_seed: okm
- })
- }
-}
-
enum InboundHTLCRemovalReason {
FailRelay(msgs::OnionErrorPacket),
FailMalformed(([u8; 32], u16)),
channel_value_satoshis: u64,
local_keys: ChannelKeys,
+ shutdown_pubkey: PublicKey,
// Our commitment numbers start at 2^48-1 and count down, whereas the ones used in transaction
// generation start at 0 and count up...this simplifies some parts of implementation at the
}
// Constructors:
- pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Result<Channel, APIError> {
+ pub fn new_outbound(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Result<Channel, APIError> {
+ let chan_keys = keys_provider.get_channel_keys(false);
+
if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(APIError::APIMisuseError{err: "funding value > 2^24"});
}
let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let secp_ctx = Secp256k1::new();
- let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &chan_keys.channel_monitor_claim_key).serialize());
- let our_channel_monitor_claim_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script();
- let channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key,
- &PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key),
- &chan_keys.htlc_base_key,
- BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script);
+ let channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &chan_keys.delayed_payment_base_key,
+ &chan_keys.htlc_base_key, BREAKDOWN_TIMEOUT,
+ keys_provider.get_destination_script());
Ok(Channel {
user_id: user_id,
channel_value_satoshis: channel_value_satoshis,
local_keys: chan_keys,
+ shutdown_pubkey: keys_provider.get_shutdown_pubkey(),
cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
cur_remote_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat: channel_value_satoshis * 1000 - push_msat,
/// Creates a new channel from a remote sides' request for one.
/// Assumes chain_hash has already been checked and corresponds with what we expect!
- pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>) -> Result<Channel, ChannelError> {
+ pub fn new_from_req(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>) -> Result<Channel, ChannelError> {
+ let chan_keys = keys_provider.get_channel_keys(true);
+
// Check sanity of message fields:
if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(ChannelError::Close("funding value > 2^24"));
}
let secp_ctx = Secp256k1::new();
- let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &chan_keys.channel_monitor_claim_key).serialize());
- let our_channel_monitor_claim_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script();
- let mut channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key,
- &PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key),
- &chan_keys.htlc_base_key,
- BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script);
+ let mut channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &chan_keys.delayed_payment_base_key,
+ &chan_keys.htlc_base_key, BREAKDOWN_TIMEOUT,
+ keys_provider.get_destination_script());
channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);
channel_monitor.set_their_to_self_delay(msg.to_self_delay);
announce_publicly: their_announce,
local_keys: chan_keys,
+ shutdown_pubkey: keys_provider.get_shutdown_pubkey(),
cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
cur_remote_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat: msg.push_msat,
#[inline]
fn get_closing_scriptpubkey(&self) -> Script {
- let our_channel_close_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.channel_close_key).serialize());
+ let our_channel_close_key_hash = Hash160::from_data(&self.shutdown_pubkey.serialize());
Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script()
}
#[cfg(test)]
mod tests {
- use bitcoin::util::hash::Sha256dHash;
+ use bitcoin::util::hash::{Sha256dHash, Hash160};
use bitcoin::util::bip143;
use bitcoin::network::serialize::serialize;
- use bitcoin::blockdata::script::Script;
+ use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::transaction::Transaction;
+ use bitcoin::blockdata::opcodes;
use hex;
use ln::channelmanager::HTLCSource;
use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys};
use ln::channel::MAX_FUNDING_SATOSHIS;
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
+ use chain::keysinterface::KeysInterface;
use chain::transaction::OutPoint;
use util::test_utils;
use util::logger::Logger;
"MAX_FUNDING_SATOSHIS is greater than all satoshis on existence");
}
+ struct Keys {
+ chan_keys: ChannelKeys,
+ }
+ impl KeysInterface for Keys {
+ fn get_node_secret(&self) -> SecretKey { panic!(); }
+ fn get_destination_script(&self) -> Script {
+ let secp_ctx = Secp256k1::signing_only();
+ let channel_monitor_claim_key = SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
+ let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
+ Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
+ }
+
+ fn get_shutdown_pubkey(&self) -> PublicKey {
+ let secp_ctx = Secp256k1::signing_only();
+ let channel_close_key = SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
+ PublicKey::from_secret_key(&secp_ctx, &channel_close_key)
+ }
+
+ fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys { self.chan_keys.clone() }
+ }
+
#[test]
fn outbound_commitment_test() {
// Test vectors from BOLT 3 Appendix C:
// These aren't set in the test vectors:
revocation_base_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
- channel_close_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
- channel_monitor_claim_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
commitment_seed: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
};
assert_eq!(PublicKey::from_secret_key(&secp_ctx, &chan_keys.funding_key).serialize()[..],
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
+ let keys_provider: Arc<KeysInterface> = Arc::new(Keys { chan_keys });
let their_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
- let mut chan = Channel::new_outbound(&feeest, chan_keys, their_node_id, 10000000, 100000, false, 42, Arc::clone(&logger)).unwrap(); // Nothing uses their network key in this test
+ let mut chan = Channel::new_outbound(&feeest, &keys_provider, their_node_id, 10000000, 100000, false, 42, Arc::clone(&logger)).unwrap(); // Nothing uses their network key in this test
chan.their_to_self_delay = 144;
chan.our_dust_limit_satoshis = 546;