From 9069bc0ea8b7fdaa9ee276d78fb0610157edbcf2 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 29 Apr 2021 22:29:36 +0000 Subject: [PATCH] Support secp256k1 RecoverableSignatures --- c-bindings-gen/src/types.rs | 6 ++++++ lightning-c-bindings/src/c_types/mod.rs | 28 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 9ef83f2..1b38108 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -781,6 +781,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { match ty { "()" => true, "crate::c_types::Signature" => true, + "crate::c_types::RecoverableSignature" => true, "crate::c_types::TxOut" => true, _ => false, } @@ -819,6 +820,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey"), "bitcoin::secp256k1::Signature" => Some("crate::c_types::Signature"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some("crate::c_types::RecoverableSignature"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some("*const [u8; 32]"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -894,6 +896,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { => Some(""), "bitcoin::secp256k1::Signature" if is_ref => Some("&"), "bitcoin::secp256k1::Signature" => Some(""), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(""), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some("&::bitcoin::secp256k1::key::SecretKey::from_slice(&unsafe { *"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -954,6 +957,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some(".into_rust()"), "bitcoin::secp256k1::Signature" => Some(".into_rust()"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(".into_rust()"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if !is_ref => Some(".into_rust()"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -1033,6 +1037,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey::from_rust(&"), "bitcoin::secp256k1::Signature" => Some("crate::c_types::Signature::from_rust(&"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some("crate::c_types::RecoverableSignature::from_rust(&"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some(""), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -1102,6 +1107,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some(")"), "bitcoin::secp256k1::Signature" => Some(")"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(")"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if !is_ref => Some(")"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" diff --git a/lightning-c-bindings/src/c_types/mod.rs b/lightning-c-bindings/src/c_types/mod.rs index cd96dff..b28bc80 100644 --- a/lightning-c-bindings/src/c_types/mod.rs +++ b/lightning-c-bindings/src/c_types/mod.rs @@ -9,6 +9,8 @@ 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 @@ -85,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 { -- 2.30.2