From 5f8dfd37b766a318fa49f886063e6a14a7c4b32e Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Wed, 13 Jan 2021 13:48:36 +0900 Subject: [PATCH 1/6] Use rust-bitcoin ecdsa-adaptor version --- background-processor/Cargo.toml | 10 ++++++---- lightning-block-sync/Cargo.toml | 4 ++-- lightning-net-tokio/Cargo.toml | 6 +++--- lightning-persister/Cargo.toml | 10 ++++++---- lightning/Cargo.toml | 8 +++++--- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/background-processor/Cargo.toml b/background-processor/Cargo.toml index 89ac2168161..3e586fee706 100644 --- a/background-processor/Cargo.toml +++ b/background-processor/Cargo.toml @@ -10,13 +10,15 @@ Utilities to perform required background tasks for Rust Lightning. edition = "2018" [dependencies] -bitcoin = "0.26" -lightning = { version = "0.0.13", path = "../lightning", features = ["allow_wallclock_use"] } +bitcoin = {version="0.26.0-adaptor.0", git = "https://github.com/p2pderivatives/rust-bitcoin", branch = "ecdsa-adaptor", package="bitcoin"} +lightning = { version = "0.0.13-adaptor.0", path = "../lightning" } lightning-persister = { version = "0.0.13", path = "../lightning-persister" } [dev-dependencies] -lightning = { version = "0.0.13", path = "../lightning", features = ["_test_utils"] } +lightning = { version = "0.0.13-adaptor.0", path = "../lightning", features = ["_test_utils"] } [dev-dependencies.bitcoin] -version = "0.26" +version = "0.26.0-adaptor.0" +git = "https://github.com/p2pderivatives/rust-bitcoin" +branch = "ecdsa-adaptor" features = ["bitcoinconsensus"] diff --git a/lightning-block-sync/Cargo.toml b/lightning-block-sync/Cargo.toml index ac750bcc473..2fc833cf243 100644 --- a/lightning-block-sync/Cargo.toml +++ b/lightning-block-sync/Cargo.toml @@ -14,8 +14,8 @@ rest-client = [ "serde", "serde_json", "chunked_transfer" ] rpc-client = [ "serde", "serde_json", "chunked_transfer" ] [dependencies] -bitcoin = "0.26" -lightning = { version = "0.0.13", path = "../lightning" } +bitcoin = {version="0.26.0-adaptor.0", git = "https://github.com/p2pderivatives/rust-bitcoin", branch = "ecdsa-adaptor", package="bitcoin"} +lightning = { version = "0.0.13-adaptor.0", path = "../lightning" } tokio = { version = "1.0", features = [ "io-util", "net" ], optional = true } serde = { version = "1.0", features = ["derive"], optional = true } serde_json = { version = "1.0", optional = true } diff --git a/lightning-net-tokio/Cargo.toml b/lightning-net-tokio/Cargo.toml index b5eba8a7cce..ea5e99fe9e3 100644 --- a/lightning-net-tokio/Cargo.toml +++ b/lightning-net-tokio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-net-tokio" -version = "0.0.13" +version = "0.0.13-adaptor.0" authors = ["Matt Corallo"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-bitcoin/rust-lightning/" @@ -11,8 +11,8 @@ For Rust-Lightning clients which wish to make direct connections to Lightning P2 edition = "2018" [dependencies] -bitcoin = "0.26" -lightning = { version = "0.0.13", path = "../lightning" } +bitcoin = {version="0.26.0-adaptor.0", git = "https://github.com/p2pderivatives/rust-bitcoin", branch = "ecdsa-adaptor", package="bitcoin"} +lightning = { version = "0.0.13-adaptor.0", path = "../lightning" } tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "sync", "net", "time" ] } [dev-dependencies] diff --git a/lightning-persister/Cargo.toml b/lightning-persister/Cargo.toml index a6e7242b0cb..f889f4c9a99 100644 --- a/lightning-persister/Cargo.toml +++ b/lightning-persister/Cargo.toml @@ -12,16 +12,18 @@ Utilities to manage Rust-Lightning channel data persistence and retrieval. unstable = ["lightning/unstable"] [dependencies] -bitcoin = "0.26" -lightning = { version = "0.0.13", path = "../lightning" } +bitcoin = {version="0.26.0-adaptor.0", git = "https://github.com/p2pderivatives/rust-bitcoin", branch = "ecdsa-adaptor", package="bitcoin"} +lightning = { version = "0.0.13-adaptor.0", path = "../lightning" } libc = "0.2" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["winbase"] } [dev-dependencies.bitcoin] -version = "0.26" +version = "0.26.0-adaptor.0" +git = "https://github.com/p2pderivatives/rust-bitcoin" +branch = "ecdsa-adaptor" features = ["bitcoinconsensus"] [dev-dependencies] -lightning = { version = "0.0.13", path = "../lightning", features = ["_test_utils"] } +lightning = { version = "0.0.13-adaptor.0", path = "../lightning", features = ["_test_utils"] } diff --git a/lightning/Cargo.toml b/lightning/Cargo.toml index da9ac51a79f..6b8ac05f500 100644 --- a/lightning/Cargo.toml +++ b/lightning/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning" -version = "0.0.13" +version = "0.0.13-adaptor.0" authors = ["Matt Corallo"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-bitcoin/rust-lightning/" @@ -27,13 +27,15 @@ unsafe_revoked_tx_signing = [] unstable = [] [dependencies] -bitcoin = "0.26" +bitcoin = {version="0.26.0-adaptor.0", git = "https://github.com/p2pderivatives/rust-bitcoin", branch = "ecdsa-adaptor", package="bitcoin"} hex = { version = "0.3", optional = true } regex = { version = "0.1.80", optional = true } [dev-dependencies.bitcoin] -version = "0.26" +version = "0.26.0-adaptor.0" +git = "https://github.com/p2pderivatives/rust-bitcoin" +branch = "ecdsa-adaptor" features = ["bitcoinconsensus"] [dev-dependencies] From 705a69566abfad96ab11f9455ee94634a4966aee Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Wed, 13 Jan 2021 13:54:48 +0900 Subject: [PATCH 2/6] Make necessary struct and macros public --- lightning/src/ln/mod.rs | 2 +- lightning/src/util/mod.rs | 3 +- lightning/src/util/ser.rs | 19 ++++++++--- lightning/src/util/ser_macros.rs | 57 ++++++++++++++++++-------------- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 3827cea84e0..b0265683e44 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -36,7 +36,7 @@ pub(crate) mod peer_channel_encryptor; mod channel; mod onion_utils; -mod wire; +pub mod wire; // Older rustc (which we support) refuses to let us call the get_payment_preimage_hash!() macro // without the node parameter being mut. This is incorrect, and thus newer rustcs will complain diff --git a/lightning/src/util/mod.rs b/lightning/src/util/mod.rs index 04b77872c89..0c38da8e107 100644 --- a/lightning/src/util/mod.rs +++ b/lightning/src/util/mod.rs @@ -24,8 +24,9 @@ pub(crate) mod chacha20poly1305rfc; pub(crate) mod transaction_utils; pub(crate) mod scid_utils; +/// Macros for serialization #[macro_use] -pub(crate) mod ser_macros; +pub mod ser_macros; /// Logging macro utilities. #[macro_use] diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index b718e228c93..c3612dea632 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -84,7 +84,7 @@ impl Writer for VecWriter { /// Writer that only tracks the amount of data written - useful if you need to calculate the length /// of some data when serialized but don't yet need the full data. -pub(crate) struct LengthCalculatingWriter(pub usize); +pub struct LengthCalculatingWriter(pub usize); impl Writer for LengthCalculatingWriter { #[inline] fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> { @@ -97,20 +97,23 @@ impl Writer for LengthCalculatingWriter { /// Essentially std::io::Take but a bit simpler and with a method to walk the underlying stream /// forward to ensure we always consume exactly the fixed length specified. -pub(crate) struct FixedLengthReader { +pub struct FixedLengthReader { read: R, bytes_read: u64, total_bytes: u64, } impl FixedLengthReader { + /// Create a new FixedLengthReader. pub fn new(read: R, total_bytes: u64) -> Self { Self { read, bytes_read: 0, total_bytes } } + /// Whether the reader has remaining bytes to read. pub fn bytes_remain(&mut self) -> bool { self.bytes_read != self.total_bytes } + /// Eat the remaining of the reader. pub fn eat_remaining(&mut self) -> Result<(), DecodeError> { ::std::io::copy(self, &mut ::std::io::sink()).unwrap(); if self.bytes_read != self.total_bytes { @@ -120,6 +123,7 @@ impl FixedLengthReader { } } } + impl Read for FixedLengthReader { fn read(&mut self, dest: &mut [u8]) -> Result { if self.total_bytes == self.bytes_read { @@ -139,16 +143,23 @@ impl Read for FixedLengthReader { /// A Read which tracks whether any bytes have been read at all. This allows us to distinguish /// between "EOF reached before we started" and "EOF reached mid-read". -pub(crate) struct ReadTrackingReader { +pub struct ReadTrackingReader { read: R, + /// Whether any bytes have been read or not. pub have_read: bool, } + +/// Implementation for ReadTrackingReader. impl ReadTrackingReader { + /// Create a new ReadTrackingReader. pub fn new(read: R) -> Self { Self { read, have_read: false } } } + +/// Implements the Read trait for ReadTrackingReader. impl Read for ReadTrackingReader { + /// Read into the given buffer. fn read(&mut self, dest: &mut [u8]) -> Result { match self.read.read(dest) { Ok(0) => Ok(0), @@ -244,7 +255,7 @@ impl Readable for U48 { /// encoded in several different ways, which we must check for at deserialization-time. Thus, if /// you're looking for an example of a variable-length integer to use for your own project, move /// along, this is a rather poor design. -pub(crate) struct BigSize(pub u64); +pub struct BigSize(pub u64); impl Writeable for BigSize { #[inline] fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index ceabcc1ddbe..e8288167e11 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -7,9 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. +#[macro_export] +/// Encode a tlv macro_rules! encode_tlv { ($stream: expr, {$(($type: expr, $field: expr)),*}) => { { - use util::ser::{BigSize, LengthCalculatingWriter}; + use $crate::util::ser::{BigSize, LengthCalculatingWriter}; $( BigSize($type).write($stream)?; let mut len_calc = LengthCalculatingWriter(0); @@ -20,9 +22,11 @@ macro_rules! encode_tlv { } } } +#[macro_export] +/// Encode a tlv with a varint length prefixed macro_rules! encode_varint_length_prefixed_tlv { ($stream: expr, {$(($type: expr, $field: expr)),*}) => { { - use util::ser::{BigSize, LengthCalculatingWriter}; + use $crate::util::ser::{BigSize, LengthCalculatingWriter}; let mut len = LengthCalculatingWriter(0); { $( @@ -41,19 +45,21 @@ macro_rules! encode_varint_length_prefixed_tlv { } } } +#[macro_export] +/// Decode a tlv macro_rules! decode_tlv { ($stream: expr, {$(($reqtype: expr, $reqfield: ident)),*}, {$(($type: expr, $field: ident)),*}) => { { - use ln::msgs::DecodeError; + use $crate::ln::msgs::DecodeError; let mut last_seen_type: Option = None; 'tlv_read: loop { - use util::ser; + use $crate::util::ser; // First decode the type of this TLV: let typ: ser::BigSize = { // We track whether any bytes were read during the consensus_decode call to // determine whether we should break or return ShortRead if we get an // UnexpectedEof. This should in every case be largely cosmetic, but its nice to - // pass the TLV test vectors exactly, which requre this distinction. + // pass the TLV test vectors exactly, which requires this distinction. let mut tracking_reader = ser::ReadTrackingReader::new($stream); match ser::Readable::read(&mut tracking_reader) { Err(DecodeError::ShortRead) => { @@ -84,26 +90,29 @@ macro_rules! decode_tlv { // Finally, read the length and value itself: let length: ser::BigSize = Readable::read($stream)?; let mut s = ser::FixedLengthReader::new($stream, length.0); - match typ.0 { - $($reqtype => { - $reqfield = ser::Readable::read(&mut s)?; - if s.bytes_remain() { - s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes - Err(DecodeError::InvalidValue)? - } - },)* - $($type => { - $field = Some(ser::Readable::read(&mut s)?); - if s.bytes_remain() { - s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes - Err(DecodeError::InvalidValue)? + loop { + $(if typ.0 == $reqtype { + $reqfield = ser::Readable::read(&mut s)?; + if s.bytes_remain() { + s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes + Err(DecodeError::InvalidValue)? + } + break; + })* + $(if typ.0 == $type { + $field = Some(ser::Readable::read(&mut s)?); + if s.bytes_remain() { + s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes + Err(DecodeError::InvalidValue)? + } + break; + })* + let x = typ.0; + if x % 2 == 0 { + Err(DecodeError::UnknownRequiredFeature)? } - },)* - x if x % 2 == 0 => { - Err(DecodeError::UnknownRequiredFeature)? - }, - _ => {}, - } + break; + } s.eat_remaining()?; } // Make sure we got to each required type after we've read every TLV: From 6ff37a1765226d21b37f4180100a9235d1c18a0f Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Wed, 13 Jan 2021 13:55:29 +0900 Subject: [PATCH 3/6] Implement readable/writable for Schnorr public key --- lightning/src/util/ser.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index c3612dea632..572b6d4eeaa 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -18,6 +18,7 @@ use std::cmp; use bitcoin::secp256k1::Signature; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; +use bitcoin::secp256k1::schnorrsig; use bitcoin::blockdata::script::Script; use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut}; use bitcoin::consensus; @@ -547,6 +548,22 @@ impl Readable for PublicKey { } } +impl Writeable for schnorrsig::PublicKey { + fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + self.serialize().write(w) + } +} + +impl Readable for schnorrsig::PublicKey { + fn read(r: &mut R) -> Result { + let buf: [u8; 33] = Readable::read(r)?; + match schnorrsig::PublicKey::from_slice(&buf) { + Ok(key) => Ok(key), + Err(_) => return Err(DecodeError::InvalidValue), + } + } +} + impl Writeable for SecretKey { fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { let mut ser = [0; 32]; From 3e62d5440467a48ea1dee838279769c747f724b9 Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Wed, 13 Jan 2021 13:55:44 +0900 Subject: [PATCH 4/6] Implement serialization for AdaptorSignature/AdaptorProof --- lightning/src/util/ser.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 572b6d4eeaa..fe89f2bf0d6 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -437,6 +437,8 @@ impl_array!(16); // for IPv6 impl_array!(32); // for channel id & hmac impl_array!(33); // for PublicKey impl_array!(64); // for Signature +impl_array!(65); // for AdaptorSignature +impl_array!(97); // for AdaptorProof impl_array!(1300); // for OnionPacket.hop_data // HashMap From 573a3d90ef71dd6689c4fd7c51b0d6614ee9a392 Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Wed, 14 Apr 2021 12:05:41 +0900 Subject: [PATCH 5/6] Add serialization of SchnorrSignature --- lightning/src/util/ser.rs | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index fe89f2bf0d6..eab4cf9cc59 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -17,6 +17,7 @@ use std::sync::Mutex; use std::cmp; use bitcoin::secp256k1::Signature; +use bitcoin::secp256k1::constants::SCHNORRSIG_SIGNATURE_SIZE; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use bitcoin::secp256k1::schnorrsig; use bitcoin::blockdata::script::Script; @@ -491,6 +492,7 @@ impl Readable for Vec { Ok(ret) } } + impl Writeable for Vec { #[inline] fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { @@ -518,6 +520,33 @@ impl Readable for Vec { } } +impl Writeable for Vec { + #[inline] + fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + (self.len() as u16).write(w)?; + for e in self.iter() { + e.write(w)?; + } + Ok(()) + } +} + +impl Readable for Vec { + #[inline] + fn read(r: &mut R) -> Result { + let len: u16 = Readable::read(r)?; + let byte_size = (len as usize) + .checked_mul(SCHNORRSIG_SIGNATURE_SIZE) + .ok_or(DecodeError::BadLengthDescriptor)?; + if byte_size > MAX_BUF_SIZE { + return Err(DecodeError::BadLengthDescriptor); + } + let mut ret = Vec::with_capacity(len as usize); + for _ in 0..len { ret.push(schnorrsig::Signature::read(r)?); } + Ok(ret) + } +} + impl Writeable for Script { fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { (self.len() as u16).write(w)?; @@ -615,6 +644,22 @@ impl Readable for Signature { } } +impl Writeable for schnorrsig::Signature { + fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + self.as_ref().write(w) + } +} + +impl Readable for schnorrsig::Signature { + fn read(r: &mut R) -> Result { + let buf: [u8; 64] = Readable::read(r)?; + match schnorrsig::Signature::from_slice(&buf) { + Ok(sig) => Ok(sig), + Err(_) => return Err(DecodeError::InvalidValue), + } + } +} + impl Writeable for PaymentPreimage { fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { self.0.write(w) From e48a223f5123a08b964ec5f5ae5d7e4839014c54 Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Wed, 14 Apr 2021 12:08:26 +0900 Subject: [PATCH 6/6] Add serialization for Vec --- lightning/src/util/ser.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index eab4cf9cc59..d690ff64e49 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -17,7 +17,7 @@ use std::sync::Mutex; use std::cmp; use bitcoin::secp256k1::Signature; -use bitcoin::secp256k1::constants::SCHNORRSIG_SIGNATURE_SIZE; +use bitcoin::secp256k1::constants::{SCHNORRSIG_SIGNATURE_SIZE, SCHNORRSIG_PUBLIC_KEY_SIZE}; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use bitcoin::secp256k1::schnorrsig; use bitcoin::blockdata::script::Script; @@ -547,6 +547,33 @@ impl Readable for Vec { } } +impl Writeable for Vec { + #[inline] + fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + (self.len() as u16).write(w)?; + for e in self.iter() { + e.write(w)?; + } + Ok(()) + } +} + +impl Readable for Vec { + #[inline] + fn read(r: &mut R) -> Result { + let len: u16 = Readable::read(r)?; + let byte_size = (len as usize) + .checked_mul(SCHNORRSIG_PUBLIC_KEY_SIZE) + .ok_or(DecodeError::BadLengthDescriptor)?; + if byte_size > MAX_BUF_SIZE { + return Err(DecodeError::BadLengthDescriptor); + } + let mut ret = Vec::with_capacity(len as usize); + for _ in 0..len { ret.push(schnorrsig::PublicKey::read(r)?); } + Ok(ret) + } +} + impl Writeable for Script { fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { (self.len() as u16).write(w)?;