#![cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))]
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use std::fmt;
use secp256k1::{PublicKey, Secp256k1, SecretKey};
use crate::NodeId;
#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct NodePubkey(
pub PublicKey
);
impl NodePubkey {
#[cfg(feature = "node_pubkey_verify")]
#[cfg_attr(docsrs, doc(cfg(feature = "node_pubkey_verify")))]
pub fn verify<H: secp256k1::ThirtyTwoByteHash + secp256k1::bitcoin_hashes::Hash, C: secp256k1::Verification>(&self, secp: &Secp256k1<C>, message: &[u8], signature: &[u8]) -> Result<(), secp256k1::Error> {
use secp256k1::{Signature, Message};
let signature = Signature::from_compact(signature)?;
let message = Message::from_hashed_data::<H>(message);
secp.verify(&message, &signature, &self.0)
}
#[cfg(feature = "node_pubkey_recovery")]
#[cfg_attr(docsrs, doc(cfg(feature = "node_pubkey_recovery")))]
pub fn verify_lightning_message<C: secp256k1::Verification>(&self, secp: &Secp256k1<C>, message: &[u8], signature: &[u8]) -> Result<(), secp256k1::Error> {
use secp256k1::Message;
use secp256k1::recovery::{RecoverableSignature, RecoveryId};
use secp256k1::bitcoin_hashes::{sha256, sha256d, HashEngine, Hash};
let (recovery_id, signature) = signature
.split_first()
.ok_or(secp256k1::Error::InvalidSignature)?;
let recovery_id = recovery_id
.checked_sub(0x1f)
.ok_or(secp256k1::Error::InvalidSignature)?;
let recovery_id = RecoveryId::from_i32(recovery_id.into())?;
let signature = RecoverableSignature::from_compact(signature, recovery_id)?;
let mut hasher = sha256::HashEngine::default();
hasher.input(b"Lightning Signed Message:");
hasher.input(message);
let hash = sha256d::Hash::from_engine(hasher);
let message = Message::from(hash);
let pubkey = secp.recover(&message, &signature)?;
if pubkey == self.0 {
Ok(())
} else {
Err(secp256k1::Error::IncorrectSignature)
}
}
fn internal_parse<S: AsRef<str> + Into<String>>(s: S) -> Result<Self, ParseError> {
match NodeId::parse_raw(s.as_ref()) {
Ok(node_id) => {
node_id.try_into()
.map_err(|error| ParseError {
input: s.into(),
reason: ParseErrorInner::Pubkey(error),
})
},
Err(error) => {
Err(ParseError {
input: s.into(),
reason: ParseErrorInner::NodeId(error),
})
}
}
}
pub fn to_node_id(&self) -> NodeId {
NodeId::from_raw_bytes(self.0.serialize())
}
pub fn from_secret_key<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &SecretKey) -> Self {
NodePubkey(PublicKey::from_secret_key(secp, sk))
}
}
impl fmt::Display for NodePubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.to_node_id(), f)
}
}
impl fmt::Debug for NodePubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.to_node_id(), f)
}
}
impl fmt::LowerHex for NodePubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.to_node_id(), f)
}
}
impl fmt::UpperHex for NodePubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(&self.to_node_id(), f)
}
}
impl TryFrom<NodeId> for NodePubkey {
type Error = secp256k1::Error;
fn try_from(value: NodeId) -> Result<Self, Self::Error> {
Ok(NodePubkey(PublicKey::from_slice(value.as_ref())?))
}
}
impl From<NodePubkey> for NodeId {
fn from(value: NodePubkey) -> Self {
value.to_node_id()
}
}
impl<'a> From<&'a NodePubkey> for NodeId {
fn from(value: &'a NodePubkey) -> Self {
value.to_node_id()
}
}
impl AsRef<PublicKey> for NodePubkey {
fn as_ref(&self) -> &PublicKey {
&self.0
}
}
impl AsMut<PublicKey> for NodePubkey {
fn as_mut(&mut self) -> &mut PublicKey {
&mut self.0
}
}
impl std::borrow::Borrow<PublicKey> for NodePubkey {
fn borrow(&self) -> &PublicKey {
&self.0
}
}
impl std::borrow::BorrowMut<PublicKey> for NodePubkey {
fn borrow_mut(&mut self) -> &mut PublicKey {
&mut self.0
}
}
impl FromStr for NodePubkey {
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::internal_parse(s)
}
}
impl<'a> TryFrom<&'a str> for NodePubkey {
type Error = ParseError;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
Self::internal_parse(s)
}
}
impl TryFrom<String> for NodePubkey {
type Error = ParseError;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::internal_parse(s)
}
}
impl TryFrom<Box<str>> for NodePubkey {
type Error = ParseError;
#[inline]
fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
Self::internal_parse(s)
}
}
impl<'a> TryFrom<&'a [u8]> for NodePubkey {
type Error = secp256k1::Error;
#[inline]
fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
Ok(NodePubkey(PublicKey::from_slice(slice)?))
}
}
impl TryFrom<Vec<u8>> for NodePubkey {
type Error = secp256k1::Error;
#[inline]
fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
(*vec).try_into()
}
}
impl TryFrom<Box<[u8]>> for NodePubkey {
type Error = secp256k1::Error;
#[inline]
fn try_from(slice: Box<[u8]>) -> Result<Self, Self::Error> {
(*slice).try_into()
}
}
impl From<NodePubkey> for [u8; 33] {
fn from(value: NodePubkey) -> Self {
value.to_node_id().into()
}
}
#[derive(Debug, Clone)]
pub struct ParseError {
input: String,
reason: ParseErrorInner,
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "failed to parse '{}' as Lightning Network node public key", self.input)
}
}
impl std::error::Error for ParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.reason {
ParseErrorInner::NodeId(error) => error.source(),
ParseErrorInner::Pubkey(error) => error.source(),
}
}
}
#[derive(Debug, Clone)]
enum ParseErrorInner {
NodeId(crate::node_id::ParseErrorInner),
Pubkey(secp256k1::Error),
}
#[cfg(feature = "parse_arg")]
mod parse_arg_impl {
use std::fmt;
use super::NodePubkey;
#[cfg_attr(docsrs, doc(cfg(feature = "parse_arg")))]
impl parse_arg::ParseArgFromStr for NodePubkey {
fn describe_type<W: fmt::Write>(mut writer: W) -> fmt::Result {
writer.write_str("a hex-encoded LN node ID (66 hex digits/33 bytes)")
}
}
}
#[cfg(all(feature = "serde", feature = "secp256k1/serde"))]
mod serde_impls {
use serde::{Serialize, Deserialize, Serializer, Deserializer};
use super::NodePubkey;
use secp256k1::PublicKey;
#[cfg_attr(all(feature = "serde", feature = "secp256k1/serde"))]
impl Serialize for NodePubkey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
Seialize::serialize(&self.0, serializer)
}
}
#[cfg_attr(all(feature = "serde", feature = "secp256k1/serde"))]
impl<'de> Deserialize<'de> for NodePubkey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
Ok(PublicKey::deserialize(deserializer)?)
}
}
}
#[cfg(feature = "postgres-types")]
mod postgres_impl {
use super::NodePubkey;
use crate::NodeId;
use postgres_types::{ToSql, FromSql, IsNull, Type};
use bytes::BytesMut;
use std::error::Error;
use std::convert::TryInto;
#[cfg_attr(docsrs, doc(cfg(feature = "postgres-types")))]
impl ToSql for NodePubkey {
fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Send + Sync + 'static>> {
self.to_node_id().to_sql(ty, out)
}
fn accepts(ty: &Type) -> bool {
<NodeId as ToSql>::accepts(ty)
}
postgres_types::to_sql_checked!();
}
#[cfg_attr(docsrs, doc(cfg(feature = "postgres-types")))]
impl<'a> FromSql<'a> for NodePubkey {
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Send + Sync + 'static>> {
NodeId::from_sql(ty, raw)?.try_into().map_err(|error| Box::new(error) as _)
}
fn accepts(ty: &Type) -> bool {
<NodeId as FromSql>::accepts(ty)
}
}
}
#[cfg(feature = "slog")]
mod slog_impl {
use super::NodePubkey;
use slog::{Key, Value, Record, Serializer};
#[cfg_attr(docsrs, doc(cfg(feature = "slog")))]
impl Value for NodePubkey {
fn serialize(&self, _rec: &Record, key: Key, serializer: &mut dyn Serializer) -> slog::Result {
serializer.emit_arguments(key, &format_args!("{}", self))
}
}
impl_error_value!(super::ParseError);
}