1use std::io;
23use std::str::FromStr;
24
25use amplify::hex::FromHex;
26use amplify::{hex, Bytes, Wrapper};
27use secp256k1::PublicKey;
28use strict_encoding::{
29 DecodeError, ReadStruct, ReadTuple, StrictDecode, StrictEncode, TypedRead, TypedWrite,
30 WriteStruct,
31};
32
33use crate::LIB_NAME_BITCOIN;
34
35#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
36#[display(doc_comments)]
37pub enum PubkeyParseError<const LEN: usize> {
38 #[from]
39 Hex(hex::Error),
40 #[from]
41 InvalidPubkey(InvalidPubkey<LEN>),
42}
43
44#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, From, Error)]
45pub enum InvalidPubkey<const LEN: usize> {
46 #[from(secp256k1::Error)]
47 #[display("invalid public key")]
48 Unspecified,
49
50 #[from]
51 #[display("invalid public key {0:x}")]
52 Specified(Bytes<LEN>),
53}
54
55#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
56#[wrapper(Deref, LowerHex, Display)]
57#[wrapper_mut(DerefMut)]
58#[derive(StrictType, StrictDumb)]
59#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self::dumb())]
60#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
61pub struct CompressedPk(PublicKey);
62
63impl CompressedPk {
64 fn dumb() -> Self { Self(PublicKey::from_slice(&[2u8; 33]).unwrap()) }
65
66 pub fn from_byte_array(data: [u8; 33]) -> Result<Self, InvalidPubkey<33>> {
67 PublicKey::from_slice(&data).map(Self).map_err(|_| InvalidPubkey::Specified(data.into()))
68 }
69 pub fn to_byte_array(&self) -> [u8; 33] { self.0.serialize() }
70
71 pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, InvalidPubkey<33>> {
72 Ok(CompressedPk(PublicKey::from_slice(bytes.as_ref())?))
73 }
74}
75
76impl StrictEncode for CompressedPk {
77 fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
78 let bytes = Bytes::<33>::from(self.0.serialize());
79 writer.write_newtype::<Self>(&bytes)
80 }
81}
82
83impl StrictDecode for CompressedPk {
84 fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
85 reader.read_tuple(|r| {
86 let bytes: Bytes<33> = r.read_field()?;
87 PublicKey::from_slice(bytes.as_slice())
88 .map(Self)
89 .map_err(|_| InvalidPubkey::Specified(bytes).into())
90 })
91 }
92}
93
94impl FromStr for CompressedPk {
95 type Err = PubkeyParseError<33>;
96
97 fn from_str(s: &str) -> Result<Self, Self::Err> {
98 let data = <[u8; 33]>::from_hex(s)?;
99 let pk = Self::from_byte_array(data)?;
100 Ok(pk)
101 }
102}
103
104#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
105#[wrapper(Deref, LowerHex, Display)]
106#[wrapper_mut(DerefMut)]
107#[derive(StrictType, StrictDumb)]
108#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self::dumb())]
109#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
110pub struct UncompressedPk(PublicKey);
111
112impl UncompressedPk {
113 fn dumb() -> Self { Self(PublicKey::from_slice(&[2u8; 33]).unwrap()) }
114
115 pub fn from_byte_array(data: [u8; 65]) -> Result<Self, InvalidPubkey<65>> {
116 PublicKey::from_slice(&data).map(Self).map_err(|_| InvalidPubkey::Specified(data.into()))
117 }
118 pub fn to_byte_array(&self) -> [u8; 65] { self.0.serialize_uncompressed() }
119}
120
121impl StrictEncode for UncompressedPk {
122 fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
123 let bytes = Bytes::<65>::from(self.0.serialize_uncompressed());
124 writer.write_newtype::<Self>(&bytes)
125 }
126}
127
128impl StrictDecode for UncompressedPk {
129 fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
130 reader.read_tuple(|r| {
131 let bytes: Bytes<65> = r.read_field()?;
132 PublicKey::from_slice(bytes.as_slice())
133 .map(Self)
134 .map_err(|_| InvalidPubkey::Specified(bytes).into())
135 })
136 }
137}
138
139impl FromStr for UncompressedPk {
140 type Err = PubkeyParseError<65>;
141
142 fn from_str(s: &str) -> Result<Self, Self::Err> {
143 let data = <[u8; 65]>::from_hex(s)?;
144 let pk = Self::from_byte_array(data)?;
145 Ok(pk)
146 }
147}
148
149#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
150#[wrapper(Deref, LowerHex, Display)]
151#[wrapper_mut(DerefMut)]
152#[derive(StrictType, StrictDumb)]
153#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self::dumb())]
154#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
155pub struct LegacyPk {
156 pub compressed: bool,
157 #[wrap]
158 pub pubkey: PublicKey,
159}
160
161impl From<PublicKey> for LegacyPk {
162 fn from(pk: PublicKey) -> Self { LegacyPk::compressed(pk) }
163}
164
165impl From<CompressedPk> for LegacyPk {
166 fn from(pk: CompressedPk) -> Self { LegacyPk::compressed(pk.0) }
167}
168
169impl From<UncompressedPk> for LegacyPk {
170 fn from(pk: UncompressedPk) -> Self { LegacyPk::uncompressed(pk.0) }
171}
172
173impl LegacyPk {
174 fn dumb() -> Self { Self::compressed(PublicKey::from_slice(&[2u8; 33]).unwrap()) }
175
176 pub const fn compressed(pubkey: PublicKey) -> Self {
177 LegacyPk {
178 compressed: true,
179 pubkey,
180 }
181 }
182
183 pub const fn uncompressed(pubkey: PublicKey) -> Self {
184 LegacyPk {
185 compressed: false,
186 pubkey,
187 }
188 }
189
190 pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, InvalidPubkey<65>> {
191 let bytes = bytes.as_ref();
192 let pubkey = PublicKey::from_slice(bytes)?;
193 Ok(match bytes.len() {
194 33 => Self::compressed(pubkey),
195 65 => Self::uncompressed(pubkey),
196 _ => unreachable!(),
197 })
198 }
199
200 pub fn to_vec(&self) -> Vec<u8> {
201 match self.compressed {
202 true => self.pubkey.serialize().to_vec(),
203 false => self.pubkey.serialize_uncompressed().to_vec(),
204 }
205 }
206}
207
208impl StrictEncode for LegacyPk {
209 fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
210 writer.write_struct::<Self>(|w| {
211 let bytes = Bytes::<33>::from(self.pubkey.serialize());
212 Ok(w.write_field(fname!("compressed"), &self.compressed)?
213 .write_field(fname!("pubkey"), &bytes)?
214 .complete())
215 })
216 }
217}
218
219impl StrictDecode for LegacyPk {
220 fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
221 reader.read_struct(|r| {
222 let compressed = r.read_field(fname!("compressed"))?;
223 let bytes: Bytes<33> = r.read_field(fname!("pubkey"))?;
224 let pubkey = PublicKey::from_slice(bytes.as_slice())
225 .map_err(|_| InvalidPubkey::Specified(bytes))?;
226 Ok(LegacyPk { compressed, pubkey })
227 })
228 }
229}
230
231impl FromStr for LegacyPk {
232 type Err = PubkeyParseError<65>;
233
234 fn from_str(s: &str) -> Result<Self, Self::Err> {
235 let data = Vec::<u8>::from_hex(s)?;
236 let pk = Self::from_bytes(data)?;
237 Ok(pk)
238 }
239}