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(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}