bc/
pubkeys.rs

1// Bitcoin protocol consensus library.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2019-2024 by
6//     Dr Maxim Orlovsky <orlovsky@lnp-bp.org>
7//
8// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved.
9//
10// Licensed under the Apache License, Version 2.0 (the "License");
11// you may not use this file except in compliance with the License.
12// You may obtain a copy of the License at
13//
14//     http://www.apache.org/licenses/LICENSE-2.0
15//
16// Unless required by applicable law or agreed to in writing, software
17// distributed under the License is distributed on an "AS IS" BASIS,
18// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19// See the License for the specific language governing permissions and
20// limitations under the License.
21
22use 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}