near_sdk/types/
public_key.rs

1use borsh::{BorshDeserialize, BorshSerialize};
2use bs58::decode::Error as B58Error;
3use near_sdk_macros::near;
4use std::{convert::TryFrom, io};
5
6/// PublicKey curve
7#[near(inside_nearsdk, serializers=[borsh(use_discriminant = true)])]
8#[derive(Debug, Clone, Copy, PartialOrd, Ord, Eq, PartialEq)]
9#[repr(u8)]
10pub enum CurveType {
11    ED25519 = 0,
12    SECP256K1 = 1,
13}
14
15impl CurveType {
16    fn from_u8(val: u8) -> Result<Self, ParsePublicKeyError> {
17        match val {
18            0 => Ok(CurveType::ED25519),
19            1 => Ok(CurveType::SECP256K1),
20            _ => Err(ParsePublicKeyError { kind: ParsePublicKeyErrorKind::UnknownCurve }),
21        }
22    }
23
24    /// Get the length of bytes associated to this CurveType
25    const fn data_len(&self) -> usize {
26        match self {
27            CurveType::ED25519 => 32,
28            CurveType::SECP256K1 => 64,
29        }
30    }
31}
32
33impl std::str::FromStr for CurveType {
34    type Err = ParsePublicKeyError;
35
36    fn from_str(value: &str) -> Result<Self, Self::Err> {
37        if value.eq_ignore_ascii_case("ed25519") {
38            Ok(CurveType::ED25519)
39        } else if value.eq_ignore_ascii_case("secp256k1") {
40            Ok(CurveType::SECP256K1)
41        } else {
42            Err(ParsePublicKeyError { kind: ParsePublicKeyErrorKind::UnknownCurve })
43        }
44    }
45}
46
47#[cfg(all(not(target_arch = "wasm32"), feature = "unit-testing"))]
48#[cfg(test)]
49impl TryFrom<PublicKey> for near_crypto::PublicKey {
50    type Error = ParsePublicKeyError;
51
52    fn try_from(public_key: PublicKey) -> Result<Self, Self::Error> {
53        let curve_type = CurveType::from_u8(public_key.data[0])?;
54        let expected_len = curve_type.data_len();
55
56        let key_bytes = public_key.into_bytes();
57        if key_bytes.len() != expected_len + 1 {
58            return Err(ParsePublicKeyError {
59                kind: ParsePublicKeyErrorKind::InvalidLength(key_bytes.len()),
60            });
61        }
62
63        let data = &key_bytes.as_slice()[1..];
64        match curve_type {
65            CurveType::ED25519 => {
66                let public_key = near_crypto::PublicKey::ED25519(
67                    near_crypto::ED25519PublicKey::try_from(data).unwrap(),
68                );
69                Ok(public_key)
70            }
71            CurveType::SECP256K1 => {
72                let public_key = near_crypto::PublicKey::SECP256K1(
73                    near_crypto::Secp256K1PublicKey::try_from(data).unwrap(),
74                );
75                Ok(public_key)
76            }
77        }
78    }
79}
80
81/// Public key in a binary format with base58 string serialization with human-readable curve.
82/// The key types currently supported are `secp256k1` and `ed25519`.
83///
84/// Ed25519 public keys accepted are 32 bytes and secp256k1 keys are the uncompressed 64 format.
85///
86/// # Example
87/// ```
88/// use near_sdk::PublicKey;
89///
90/// // Compressed ed25519 key
91/// let ed: PublicKey = "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp".parse()
92///             .unwrap();
93///
94/// // Uncompressed secp256k1 key
95/// let secp256k1: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj"
96///             .parse()
97///             .unwrap();
98/// ```
99#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, BorshSerialize, Hash)]
100#[cfg_attr(feature = "abi", derive(borsh::BorshSchema))]
101pub struct PublicKey {
102    data: Vec<u8>,
103}
104
105impl PublicKey {
106    fn split_key_type_data(value: &str) -> Result<(CurveType, &str), ParsePublicKeyError> {
107        if let Some(idx) = value.find(':') {
108            let (prefix, key_data) = value.split_at(idx);
109            Ok((prefix.parse::<CurveType>()?, &key_data[1..]))
110        } else {
111            // If there is no Default is ED25519.
112            Ok((CurveType::ED25519, value))
113        }
114    }
115
116    pub fn from_parts(curve: CurveType, data: Vec<u8>) -> Result<Self, ParsePublicKeyError> {
117        let expected_length = curve.data_len();
118        if data.len() != expected_length {
119            return Err(ParsePublicKeyError {
120                kind: ParsePublicKeyErrorKind::InvalidLength(data.len()),
121            });
122        }
123        let mut bytes = Vec::with_capacity(1 + expected_length);
124        bytes.push(curve as u8);
125        bytes.extend(data);
126
127        Ok(Self { data: bytes })
128    }
129
130    /// Returns a byte slice of this `PublicKey`'s contents.
131    pub fn as_bytes(&self) -> &[u8] {
132        &self.data
133    }
134
135    /// Converts a `PublicKey` into a byte vector.
136    pub fn into_bytes(self) -> Vec<u8> {
137        self.data
138    }
139
140    /// Get info about the CurveType for this public key
141    pub fn curve_type(&self) -> CurveType {
142        CurveType::from_u8(self.data[0]).unwrap_or_else(|_| crate::env::abort())
143    }
144}
145
146impl From<PublicKey> for Vec<u8> {
147    fn from(v: PublicKey) -> Vec<u8> {
148        v.data
149    }
150}
151
152impl TryFrom<Vec<u8>> for PublicKey {
153    type Error = ParsePublicKeyError;
154
155    fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
156        if data.is_empty() {
157            return Err(ParsePublicKeyError {
158                kind: ParsePublicKeyErrorKind::InvalidLength(data.len()),
159            });
160        }
161
162        let curve = CurveType::from_u8(data[0])?;
163        if data.len() != curve.data_len() + 1 {
164            return Err(ParsePublicKeyError {
165                kind: ParsePublicKeyErrorKind::InvalidLength(data.len()),
166            });
167        }
168        Ok(Self { data })
169    }
170}
171
172impl serde::Serialize for PublicKey {
173    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
174    where
175        S: serde::Serializer,
176    {
177        serializer.serialize_str(&String::from(self))
178    }
179}
180
181impl BorshDeserialize for PublicKey {
182    fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
183        <Vec<u8> as BorshDeserialize>::deserialize_reader(reader).and_then(|s| {
184            Self::try_from(s).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
185        })
186    }
187}
188
189impl<'de> serde::Deserialize<'de> for PublicKey {
190    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
191    where
192        D: serde::Deserializer<'de>,
193    {
194        let s: String = serde::Deserialize::deserialize(deserializer)?;
195        s.parse::<PublicKey>().map_err(serde::de::Error::custom)
196    }
197}
198
199#[cfg(feature = "abi")]
200impl schemars::JsonSchema for PublicKey {
201    fn is_referenceable() -> bool {
202        false
203    }
204
205    fn schema_name() -> String {
206        String::schema_name()
207    }
208
209    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
210        String::json_schema(gen)
211    }
212}
213
214impl From<&PublicKey> for String {
215    fn from(str_public_key: &PublicKey) -> Self {
216        match str_public_key.curve_type() {
217            CurveType::ED25519 => {
218                ["ed25519:", &bs58::encode(&str_public_key.data[1..]).into_string()].concat()
219            }
220            CurveType::SECP256K1 => {
221                ["secp256k1:", &bs58::encode(&str_public_key.data[1..]).into_string()].concat()
222            }
223        }
224    }
225}
226
227impl std::str::FromStr for PublicKey {
228    type Err = ParsePublicKeyError;
229
230    fn from_str(value: &str) -> Result<Self, Self::Err> {
231        let (curve, key_data) = PublicKey::split_key_type_data(value)?;
232        let data = bs58::decode(key_data).into_vec()?;
233        Self::from_parts(curve, data)
234    }
235}
236#[derive(Debug)]
237pub struct ParsePublicKeyError {
238    kind: ParsePublicKeyErrorKind,
239}
240
241#[derive(Debug)]
242enum ParsePublicKeyErrorKind {
243    InvalidLength(usize),
244    Base58(B58Error),
245    UnknownCurve,
246}
247
248impl std::fmt::Display for ParsePublicKeyError {
249    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250        match self.kind {
251            ParsePublicKeyErrorKind::InvalidLength(l) => {
252                write!(f, "invalid length of the public key, expected 32 got {l}")
253            }
254            ParsePublicKeyErrorKind::Base58(e) => write!(f, "base58 decoding error: {e}"),
255            ParsePublicKeyErrorKind::UnknownCurve => write!(f, "unknown curve kind"),
256        }
257    }
258}
259
260impl From<B58Error> for ParsePublicKeyError {
261    fn from(e: B58Error) -> Self {
262        Self { kind: ParsePublicKeyErrorKind::Base58(e) }
263    }
264}
265
266impl std::error::Error for ParsePublicKeyError {}
267
268#[cfg(test)]
269mod tests {
270    use super::*;
271    use std::convert::TryInto;
272    use std::str::FromStr;
273
274    fn expected_key() -> PublicKey {
275        let mut key = vec![CurveType::ED25519 as u8];
276        key.extend(
277            bs58::decode("6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp").into_vec().unwrap(),
278        );
279        key.try_into().unwrap()
280    }
281
282    #[test]
283    fn test_public_key_deser() {
284        let key: PublicKey =
285            serde_json::from_str("\"ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp\"")
286                .unwrap();
287        assert_eq!(key, expected_key());
288    }
289
290    #[test]
291    fn test_public_key_ser() {
292        let key: PublicKey = expected_key();
293        let actual: String = serde_json::to_string(&key).unwrap();
294        assert_eq!(actual, "\"ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp\"");
295    }
296
297    #[test]
298    fn test_public_key_from_str() {
299        let key =
300            PublicKey::from_str("ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp").unwrap();
301        assert_eq!(key, expected_key());
302    }
303
304    #[test]
305    fn test_public_key_to_string() {
306        let key: PublicKey = expected_key();
307        let actual: String = String::from(&key);
308        assert_eq!(actual, "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp");
309    }
310
311    #[test]
312    fn test_public_key_borsh_format_change() {
313        // Original struct to reference Borsh serialization from
314        #[derive(BorshSerialize, BorshDeserialize)]
315        struct PublicKeyRef(Vec<u8>);
316
317        let mut data = vec![CurveType::ED25519 as u8];
318        data.extend(
319            bs58::decode("6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp").into_vec().unwrap(),
320        );
321
322        // Test internal serialization of Vec<u8> is the same:
323        let old_key = PublicKeyRef(data.clone());
324        let old_encoded_key = borsh::to_vec(&old_key).unwrap();
325        let new_key: PublicKey = data.try_into().unwrap();
326        let new_encoded_key = borsh::to_vec(&new_key).unwrap();
327        assert_eq!(old_encoded_key, new_encoded_key);
328        assert_eq!(
329            &new_encoded_key,
330            &bs58::decode("279Zpep9MBBg4nKsVmTQE7NbXZkWdxti6HS1yzhp8qnc1ExS7gU")
331                .into_vec()
332                .unwrap()
333        );
334
335        let decoded_key = PublicKey::try_from_slice(&new_encoded_key).unwrap();
336        assert_eq!(decoded_key, new_key);
337    }
338}