X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-c-bindings%2Fsrc%2Fc_types%2Fmod.rs;h=b6b1bbf0ac85a60025ee97aa5a578059ab973f71;hb=47b7d6e36914774534f4a80315c8d38e0424a2db;hp=c4113a9647cf20f64b09d11881a626992d884d55;hpb=c35ef17b94a8f4e9e019a2b63e0ed22110671b9c;p=ldk-c-bindings diff --git a/lightning-c-bindings/src/c_types/mod.rs b/lightning-c-bindings/src/c_types/mod.rs index c4113a9..b6b1bbf 100644 --- a/lightning-c-bindings/src/c_types/mod.rs +++ b/lightning-c-bindings/src/c_types/mod.rs @@ -9,9 +9,25 @@ use bitcoin::secp256k1::key::PublicKey as SecpPublicKey; use bitcoin::secp256k1::key::SecretKey as SecpSecretKey; use bitcoin::secp256k1::Signature as SecpSignature; use bitcoin::secp256k1::Error as SecpError; +use bitcoin::secp256k1::recovery::RecoveryId; +use bitcoin::secp256k1::recovery::RecoverableSignature as SecpRecoverableSignature; +use bitcoin::bech32; use std::convert::TryInto; // Bindings need at least rustc 1.34 +/// Integer in the range `0..32` +#[derive(PartialEq, Eq, Copy, Clone)] +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct u5(u8); + +impl From for u5 { + fn from(o: bech32::u5) -> Self { Self(o.to_u8()) } +} +impl Into for u5 { + fn into(self) -> bech32::u5 { bech32::u5::try_from_u8(self.0).expect("u5 objects must be in the range 0..32") } +} + #[derive(Clone)] #[repr(C)] /// Represents a valid secp256k1 public key serialized in "compressed form" as a 33 byte array. @@ -71,6 +87,32 @@ impl Signature { #[allow(unused)] pub(crate) fn null() -> Self { Self { compact_form: [0; 64] } } } +#[repr(C)] +#[derive(Clone)] +/// Represents a secp256k1 signature serialized as two 32-byte numbers as well as a tag which +/// allows recovering the exact public key which created the signature given the message. +pub struct RecoverableSignature { + /// The bytes of the signature in "compact" form plus a "Recovery ID" which allows for + /// recovery. + pub serialized_form: [u8; 68], +} +impl RecoverableSignature { + pub(crate) fn from_rust(pk: &SecpRecoverableSignature) -> Self { + let (id, compact_form) = pk.serialize_compact(); + let mut serialized_form = [0; 68]; + serialized_form[0..64].copy_from_slice(&compact_form[..]); + serialized_form[64..].copy_from_slice(&id.to_i32().to_le_bytes()); + Self { serialized_form } + } + pub(crate) fn into_rust(&self) -> SecpRecoverableSignature { + let mut id = [0; 4]; + id.copy_from_slice(&self.serialized_form[64..]); + SecpRecoverableSignature::from_compact(&self.serialized_form[0..64], + RecoveryId::from_i32(i32::from_le_bytes(id)).expect("Invalid Recovery ID")) + .unwrap() + } +} + #[repr(C)] /// Represents an error returned from libsecp256k1 during validation of some secp256k1 data pub enum Secp256k1Error { @@ -156,6 +198,28 @@ impl IOError { _ => IOError::Other, } } + pub(crate) fn to_rust(&self) -> std::io::Error { + std::io::Error::new(match self { + IOError::NotFound => std::io::ErrorKind::NotFound, + IOError::PermissionDenied => std::io::ErrorKind::PermissionDenied, + IOError::ConnectionRefused => std::io::ErrorKind::ConnectionRefused, + IOError::ConnectionReset => std::io::ErrorKind::ConnectionReset, + IOError::ConnectionAborted => std::io::ErrorKind::ConnectionAborted, + IOError::NotConnected => std::io::ErrorKind::NotConnected, + IOError::AddrInUse => std::io::ErrorKind::AddrInUse, + IOError::AddrNotAvailable => std::io::ErrorKind::AddrNotAvailable, + IOError::BrokenPipe => std::io::ErrorKind::BrokenPipe, + IOError::AlreadyExists => std::io::ErrorKind::AlreadyExists, + IOError::WouldBlock => std::io::ErrorKind::WouldBlock, + IOError::InvalidInput => std::io::ErrorKind::InvalidInput, + IOError::InvalidData => std::io::ErrorKind::InvalidData, + IOError::TimedOut => std::io::ErrorKind::TimedOut, + IOError::WriteZero => std::io::ErrorKind::WriteZero, + IOError::Interrupted => std::io::ErrorKind::Interrupted, + IOError::Other => std::io::ErrorKind::Other, + IOError::UnexpectedEof => std::io::ErrorKind::UnexpectedEof, + }, "") + } } #[repr(C)] @@ -296,6 +360,10 @@ pub struct TenBytes { /** The ten bytes */ pub data: [u8; 10], } #[repr(C)] /// A 16-byte byte array. pub struct SixteenBytes { /** The sixteen bytes */ pub data: [u8; 16], } +#[derive(Clone)] +#[repr(C)] +/// A 20-byte byte array. +pub struct TwentyBytes { /** The twenty bytes */ pub data: [u8; 20], } pub(crate) struct VecWriter(pub Vec); impl lightning::util::ser::Writer for VecWriter { @@ -320,27 +388,62 @@ pub(crate) fn deserialize_obj_arg>(s } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Clone)] /// A Rust str object, ie a reference to a UTF8-valid string. /// This is *not* null-terminated so cannot be used directly as a C string! pub struct Str { /// A pointer to the string's bytes, in UTF8 encoding pub chars: *const u8, /// The number of bytes (not characters!) pointed to by `chars` - pub len: usize + pub len: usize, + /// Whether the data pointed to by `chars` should be freed or not. + pub chars_is_owned: bool, } impl Into for &'static str { fn into(self) -> Str { - Str { chars: self.as_ptr(), len: self.len() } + Str { chars: self.as_ptr(), len: self.len(), chars_is_owned: false } } } -impl Into<&'static str> for Str { - fn into(self) -> &'static str { +impl Str { + pub(crate) fn into_str(&self) -> &'static str { if self.len == 0 { return ""; } std::str::from_utf8(unsafe { std::slice::from_raw_parts(self.chars, self.len) }).unwrap() } + pub(crate) fn into_string(mut self) -> String { + let bytes = if self.len == 0 { + Vec::new() + } else if self.chars_is_owned { + let ret = unsafe { + Box::from_raw(std::slice::from_raw_parts_mut(unsafe { self.chars as *mut u8 }, self.len)) + }.into(); + self.chars_is_owned = false; + ret + } else { + let mut ret = Vec::with_capacity(self.len); + ret.extend_from_slice(unsafe { std::slice::from_raw_parts(self.chars, self.len) }); + ret + }; + String::from_utf8(bytes).unwrap() + } +} +impl Into for String { + fn into(self) -> Str { + let s = Box::leak(self.into_boxed_str()); + Str { chars: s.as_ptr(), len: s.len(), chars_is_owned: true } + } } +impl Drop for Str { + fn drop(&mut self) { + if self.chars_is_owned && self.len != 0 { + let _ = derived::CVec_u8Z { data: self.chars as *mut u8, datalen: self.len }; + } + } +} +#[no_mangle] +/// Frees the data buffer, if chars_is_owned is set and len > 0. +pub extern "C" fn Str_free(_res: Str) { } + // Note that the C++ headers memset(0) all the Templ types to avoid deallocation! // Thus, they must gracefully handle being completely null in _free.