1use core::convert::{TryFrom, TryInto};
9use core::str::FromStr;
10use core::fmt;
11use secp256k1::{PublicKey, Secp256k1, SecretKey};
12use crate::NodeId;
13
14#[cfg(feature = "alloc")]
15use alloc::{boxed::Box, string::String, vec::Vec};
16
17#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
34pub struct NodePubkey(
35 pub PublicKey
37);
38
39impl NodePubkey {
40 #[cfg(feature = "node_pubkey_verify")]
65 pub fn verify<M: Into<secp256k1::Message>, C: secp256k1::Verification>(&self, secp: &Secp256k1<C>, message: M, signature: &[u8]) -> Result<(), secp256k1::Error> {
66 use secp256k1::ecdsa::Signature;
67
68 let signature = Signature::from_compact(signature)?;
69 let message = message.into();
70
71 secp.verify_ecdsa(&message, &signature, &self.0)
72 }
73
74 #[cfg(feature = "node_pubkey_recovery")]
95 pub fn verify_lightning_message<C: secp256k1::Verification>(&self, secp: &Secp256k1<C>, message: &[u8], signature: &[u8]) -> Result<(), secp256k1::Error> {
96 use secp256k1::Message;
97 use secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
98 use secp256k1::hashes::{sha256, sha256d, HashEngine, Hash};
99
100 let (recovery_id, signature) = signature
101 .split_first()
102 .ok_or(secp256k1::Error::InvalidSignature)?;
103
104 let recovery_id = recovery_id
105 .checked_sub(0x1f)
106 .ok_or(secp256k1::Error::InvalidSignature)?;
107
108 let recovery_id = RecoveryId::from_i32(recovery_id.into())?;
109 let signature = RecoverableSignature::from_compact(signature, recovery_id)?;
110 let mut hasher = sha256::HashEngine::default();
111 hasher.input(b"Lightning Signed Message:");
112 hasher.input(message);
113 let hash = sha256d::Hash::from_engine(hasher);
114 let message = Message::from_digest(hash.to_byte_array());
115
116 let pubkey = secp.recover_ecdsa(&message, &signature)?;
117 if pubkey == self.0 {
118 Ok(())
119 } else {
120 Err(secp256k1::Error::IncorrectSignature)
121 }
122 }
123
124 #[cfg(feature = "alloc")]
126 fn internal_parse<S: AsRef<str> + Into<String>>(s: S) -> Result<Self, ParseError> {
127 match NodeId::parse_raw(s.as_ref()) {
128 Ok(node_id) => {
129 node_id.try_into()
130 .map_err(|error| ParseError {
131 input: s.into(),
132 reason: ParseErrorInner::Pubkey(error),
133 })
134 },
135 Err(error) => {
136 Err(ParseError {
137 input: s.into(),
138 reason: ParseErrorInner::NodeId(error),
139 })
140 }
141 }
142 }
143
144 #[cfg(not(feature = "alloc"))]
146 fn internal_parse<S: AsRef<str>>(s: S) -> Result<Self, ParseError> {
147 match NodeId::parse_raw(s.as_ref()) {
148 Ok(node_id) => {
149 node_id.try_into()
150 .map_err(|error| ParseError {
151 reason: ParseErrorInner::Pubkey(error),
152 })
153 },
154 Err(error) => {
155 Err(ParseError {
156 reason: ParseErrorInner::NodeId(error),
157 })
158 }
159 }
160 }
161
162 pub fn to_node_id(&self) -> NodeId {
166 NodeId::from_raw_bytes(self.0.serialize()).expect("secp256k1 always creates correct node ID")
167 }
168
169 pub fn from_secret_key<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &SecretKey) -> Self {
171 NodePubkey(PublicKey::from_secret_key(secp, sk))
172 }
173}
174
175impl fmt::Display for NodePubkey {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 fmt::Display::fmt(&self.to_node_id(), f)
179 }
180}
181
182impl fmt::Debug for NodePubkey {
183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184 fmt::Debug::fmt(&self.to_node_id(), f)
185 }
186}
187
188impl fmt::LowerHex for NodePubkey {
189 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
190 fmt::LowerHex::fmt(&self.to_node_id(), f)
191 }
192}
193
194impl fmt::UpperHex for NodePubkey {
195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 fmt::UpperHex::fmt(&self.to_node_id(), f)
197 }
198}
199
200impl TryFrom<NodeId> for NodePubkey {
201 type Error = secp256k1::Error;
202
203 fn try_from(value: NodeId) -> Result<Self, Self::Error> {
204 Ok(NodePubkey(PublicKey::from_slice(value.as_ref())?))
205 }
206}
207
208impl From<NodePubkey> for NodeId {
209 fn from(value: NodePubkey) -> Self {
210 value.to_node_id()
211 }
212}
213
214impl<'a> From<&'a NodePubkey> for NodeId {
215 fn from(value: &'a NodePubkey) -> Self {
216 value.to_node_id()
217 }
218}
219
220impl AsRef<PublicKey> for NodePubkey {
221 fn as_ref(&self) -> &PublicKey {
222 &self.0
223 }
224}
225
226impl AsMut<PublicKey> for NodePubkey {
227 fn as_mut(&mut self) -> &mut PublicKey {
228 &mut self.0
229 }
230}
231
232impl core::borrow::Borrow<PublicKey> for NodePubkey {
233 fn borrow(&self) -> &PublicKey {
234 &self.0
235 }
236}
237
238impl core::borrow::BorrowMut<PublicKey> for NodePubkey {
239 fn borrow_mut(&mut self) -> &mut PublicKey {
240 &mut self.0
241 }
242}
243
244impl FromStr for NodePubkey {
246 type Err = ParseError;
247
248 #[inline]
249 fn from_str(s: &str) -> Result<Self, Self::Err> {
250 Self::internal_parse(s)
251 }
252}
253
254impl<'a> TryFrom<&'a str> for NodePubkey {
256 type Error = ParseError;
257
258 #[inline]
259 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
260 Self::internal_parse(s)
261 }
262}
263
264#[cfg(feature = "alloc")]
266impl TryFrom<String> for NodePubkey {
267 type Error = ParseError;
268
269 #[inline]
270 fn try_from(s: String) -> Result<Self, Self::Error> {
271 Self::internal_parse(s)
272 }
273}
274
275#[cfg(feature = "alloc")]
277impl TryFrom<Box<str>> for NodePubkey {
278 type Error = ParseError;
279
280 #[inline]
281 fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
282 Self::internal_parse(s)
283 }
284}
285
286impl<'a> TryFrom<&'a [u8]> for NodePubkey {
287 type Error = secp256k1::Error;
288
289 #[inline]
290 fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
291 Ok(NodePubkey(PublicKey::from_slice(slice)?))
292 }
293}
294
295#[cfg(feature = "alloc")]
296impl TryFrom<Vec<u8>> for NodePubkey {
297 type Error = secp256k1::Error;
298
299 #[inline]
300 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
301 (*vec).try_into()
302 }
303}
304
305#[cfg(feature = "alloc")]
306impl TryFrom<Box<[u8]>> for NodePubkey {
307 type Error = secp256k1::Error;
308
309 #[inline]
310 fn try_from(slice: Box<[u8]>) -> Result<Self, Self::Error> {
311 (*slice).try_into()
312 }
313}
314
315impl From<NodePubkey> for [u8; 33] {
316 fn from(value: NodePubkey) -> Self {
317 value.to_node_id().into()
318 }
319}
320
321#[derive(Debug, Clone)]
325pub struct ParseError {
326 #[cfg(feature = "alloc")]
328 input: String,
329 reason: ParseErrorInner,
331}
332
333impl fmt::Display for ParseError {
337 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
338 write_err!(f, "failed to parse{} Lightning Network node public key", opt_fmt!("alloc", format_args!(" '{}' as", &self.input)); &self.reason)
339 }
340}
341
342#[cfg(feature = "std")]
346impl std::error::Error for ParseError {
347 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
348 Some(&self.reason)
349 }
350}
351
352#[derive(Debug, Clone)]
356enum ParseErrorInner {
357 NodeId(crate::node_id::ParseErrorInner),
359 Pubkey(secp256k1::Error),
360}
361
362impl fmt::Display for ParseErrorInner {
363 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
364 match self {
365 ParseErrorInner::NodeId(error) => write_err!(f, "invalid node ID"; error),
366 ParseErrorInner::Pubkey(error) => write_err_ext!("secp256k1_std", f, "invalid public key"; error),
367 }
368 }
369}
370
371#[cfg(feature = "std")]
372impl std::error::Error for ParseErrorInner {
373 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
374 match &self {
375 ParseErrorInner::NodeId(error) => Some(error),
376 #[cfg(feature = "secp256k1_std")]
377 ParseErrorInner::Pubkey(error) => Some(error),
378 #[cfg(not(feature = "secp256k1_std"))]
379 ParseErrorInner::Pubkey(_) => None,
380 }
381 }
382}
383
384#[cfg(feature = "parse_arg")]
386mod parse_arg_impl {
387 use core::fmt;
388 use super::NodePubkey;
389
390 impl parse_arg::ParseArgFromStr for NodePubkey {
391 fn describe_type<W: fmt::Write>(mut writer: W) -> fmt::Result {
392 writer.write_str("a hex-encoded LN node ID (66 hex digits/33 bytes)")
393 }
394 }
395}
396
397#[cfg(all(feature = "serde", feature = "secp256k1/serde"))]
398mod serde_impls {
399 use serde::{Serialize, Deserialize, Serializer, Deserializer};
400 use super::NodePubkey;
401 use secp256k1::PublicKey;
402
403 #[cfg_attr(all(feature = "serde", feature = "secp256k1/serde"))]
405 impl Serialize for NodePubkey {
406 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
407 Seialize::serialize(&self.0, serializer)
408 }
409 }
410
411 #[cfg_attr(all(feature = "serde", feature = "secp256k1/serde"))]
413 impl<'de> Deserialize<'de> for NodePubkey {
414 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
415 Ok(PublicKey::deserialize(deserializer)?)
416 }
417 }
418}
419
420#[cfg(feature = "postgres-types")]
422mod postgres_impl {
423 use alloc::boxed::Box;
424 use super::NodePubkey;
425 use crate::NodeId;
426 use postgres_types::{ToSql, FromSql, IsNull, Type};
427 use bytes::BytesMut;
428 use std::error::Error;
429 use core::convert::TryInto;
430
431 impl ToSql for NodePubkey {
435 fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Send + Sync + 'static>> {
436 self.to_node_id().to_sql(ty, out)
437 }
438
439 fn accepts(ty: &Type) -> bool {
440 <NodeId as ToSql>::accepts(ty)
441 }
442
443 postgres_types::to_sql_checked!();
444 }
445
446 impl<'a> FromSql<'a> for NodePubkey {
450 fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Send + Sync + 'static>> {
451 NodeId::from_sql(ty, raw)?.try_into().map_err(|error| Box::new(error) as _)
452 }
453
454 fn accepts(ty: &Type) -> bool {
455 <NodeId as FromSql>::accepts(ty)
456 }
457 }
458}
459
460#[cfg(feature = "slog")]
462mod slog_impl {
463 use super::NodePubkey;
464 use slog::{Key, Value, Record, Serializer};
465
466 impl Value for NodePubkey {
468 fn serialize(&self, _rec: &Record, key: Key, serializer: &mut dyn Serializer) -> slog::Result {
469 serializer.emit_arguments(key, &format_args!("{}", self))
470 }
471 }
472
473 impl_error_value!(super::ParseError);
474}
475
476#[cfg(test)]
477mod tests {
478 use super::NodePubkey;
479
480 #[test]
481 fn empty() {
482 let error = "".parse::<NodePubkey>().unwrap_err();
483 #[cfg(feature = "alloc")]
484 assert_eq!(error.input, "");
485 match &error.reason {
486 super::ParseErrorInner::NodeId(_) => (),
487 super::ParseErrorInner::Pubkey(error) => panic!("unexpected error variant: Pubkey({:?})", error),
488 }
489 }
490
491 chk_err_impl! {
492 parse_node_pubkey_error_empty, "", NodePubkey, [
493 "failed to parse '' as Lightning Network node public key",
494 "invalid node ID",
495 "invalid length (must be 66 chars)",
496 ], [
497 "failed to parse Lightning Network node public key",
498 "invalid node ID",
499 "invalid length (must be 66 chars)",
500 ];
501 }
502
503 #[cfg(any(not(feature = "std"), feature = "secp256k1_std"))]
504 chk_err_impl! {
505 parse_node_pubkey_error_invalid_pubkey, "020000000000000000000000000000000000000000000000000000000000000000", NodePubkey, [
506 "failed to parse '020000000000000000000000000000000000000000000000000000000000000000' as Lightning Network node public key",
507 "invalid public key",
508 "malformed public key",
509 ], [
510 "failed to parse Lightning Network node public key",
511 "invalid public key",
512 "malformed public key",
513 ];
514 }
515
516 #[cfg(all(feature = "std", not(feature = "secp256k1_std")))]
517 chk_err_impl! {
518 parse_node_pubkey_error_invalid_pubkey, "020000000000000000000000000000000000000000000000000000000000000000", NodePubkey, [
519 "failed to parse '020000000000000000000000000000000000000000000000000000000000000000' as Lightning Network node public key",
520 "invalid public key: malformed public key",
521 ], [
522 "irrelevant, we definitely have std and thus alloc",
523 ];
524 }
525}