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