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