ree_types/
pubkey.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use alloc::str::FromStr;
use candid::{
    types::{Serializer, Type, TypeInner},
    CandidType,
};
use ic_stable_structures::{storable::Bound, Storable};

#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Pubkey(Vec<u8>);

impl Pubkey {
    pub fn from_raw(key: Vec<u8>) -> Result<Pubkey, String> {
        if key.len() != 33 {
            return Err("invalid pubkey".to_string());
        }
        Ok(Self(key))
    }

    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }

    pub fn to_x_only_public_key(&self) -> bitcoin::XOnlyPublicKey {
        bitcoin::XOnlyPublicKey::from_slice(&self.0[1..]).expect("The inner is 33 bytes")
    }

    pub fn to_public_key(&self) -> Result<bitcoin::PublicKey, String> {
        match self.0[0] {
            0x02 | 0x03 => {
                Ok(bitcoin::PublicKey::from_slice(&self.0).expect("The inner is 33 bytes"))
            }
            _ => Err("the pubkey is deserialized from a XOnlyPublicKey".to_string()),
        }
    }
}

impl CandidType for Pubkey {
    fn _ty() -> Type {
        TypeInner::Text.into()
    }

    fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_text(&self.to_string())
    }
}

impl Storable for Pubkey {
    const BOUND: Bound = Bound::Bounded {
        max_size: 33,
        is_fixed_size: true,
    };

    fn to_bytes(&self) -> alloc::borrow::Cow<[u8]> {
        alloc::borrow::Cow::Borrowed(&self.0)
    }

    fn from_bytes(bytes: alloc::borrow::Cow<[u8]>) -> Self {
        Self::from_raw(bytes.to_vec()).expect("Couldn't deserialize pubkey from stable memory")
    }
}

impl core::fmt::Display for Pubkey {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        match self.0[0] {
            0x02 | 0x03 => {
                let key = bitcoin::PublicKey::from_slice(&self.0).expect("The inner is 33 bytes");
                write!(f, "{}", key)
            }
            _ => {
                let key = bitcoin::XOnlyPublicKey::from_slice(&self.0[1..])
                    .expect("The inner is 33 bytes");
                write!(f, "{}", key)
            }
        }
    }
}

impl FromStr for Pubkey {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let s = s.trim_start_matches("0x");
        let raw = hex::decode(s).map_err(|_| "invalid pubkey".to_string())?;
        if raw.len() == 32 {
            let v = [&[0x00], &raw[..]].concat();
            Self::from_raw(v)
        } else {
            Self::from_raw(raw)
        }
    }
}

struct PubkeyVisitor;

impl<'de> serde::de::Visitor<'de> for PubkeyVisitor {
    type Value = Pubkey;

    fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(formatter, "a 33-bytes pubkey")
    }

    fn visit_str<E>(self, value: &str) -> Result<Pubkey, E>
    where
        E: serde::de::Error,
    {
        Pubkey::from_str(value)
            .map_err(|_| E::invalid_value(serde::de::Unexpected::Str(value), &self))
    }
}

impl<'de> serde::Deserialize<'de> for Pubkey {
    fn deserialize<D>(deserializer: D) -> Result<Pubkey, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        deserializer.deserialize_any(PubkeyVisitor)
    }
}

impl serde::Serialize for Pubkey {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}