near_sdk/types/
public_key.rs1use borsh::{BorshDeserialize, BorshSerialize};
2use bs58::decode::Error as B58Error;
3use near_sdk_macros::near;
4use std::{convert::TryFrom, io};
5
6#[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 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#[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 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 pub fn as_bytes(&self) -> &[u8] {
132 &self.data
133 }
134
135 pub fn into_bytes(self) -> Vec<u8> {
137 self.data
138 }
139
140 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 #[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 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}