Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Make CurveType accessible within Base58PublicKey #453

Merged
merged 36 commits into from
Jul 18, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ecec96d
Make curve type accessible from Vec<u8>
ChaoticTempest Jun 29, 2021
1b503c1
Cargo.lock
ChaoticTempest Jun 29, 2021
ba008cc
Address #453 comments
ChaoticTempest Jun 30, 2021
06bc400
Cargo fmt
ChaoticTempest Jun 30, 2021
2259873
Preserve borsh serde between versions
ChaoticTempest Jun 30, 2021
b7647b6
Merge branch 'master' into feature/accessible-curve-type
mikedotexe Jul 4, 2021
5256823
More effeicient concat for Into<String>
ChaoticTempest Jul 6, 2021
61f6bdc
Merge branch 'feature/accessible-curve-type' of https://github.com/ne…
ChaoticTempest Jul 6, 2021
7dd2a95
Fix typo
ChaoticTempest Jul 7, 2021
0c5d1b5
Switch over str::to_lowercase() to eq_ignore_ascii_case
ChaoticTempest Jul 7, 2021
0c8ab34
Revert back to concat
ChaoticTempest Jul 7, 2021
9391b71
Merge branch 'master' into feature/accessible-curve-type
ChaoticTempest Jul 7, 2021
394af07
PublicKey[Vec<u8> => Base58PublicKey]
ChaoticTempest Jul 8, 2021
049ec67
Remove custom impl of Borsh
ChaoticTempest Jul 9, 2021
2302c7c
Cargo fmt
ChaoticTempest Jul 9, 2021
7de7b5a
as_bytes and into_bytes instead of Deref
ChaoticTempest Jul 12, 2021
fe688d2
Add changelog
ChaoticTempest Jul 12, 2021
da13929
Base58PublicKey now renamed to PublicKey
ChaoticTempest Jul 12, 2021
d65de4d
Cargo fmt
ChaoticTempest Jul 12, 2021
3f753bb
Fix expected stderr
ChaoticTempest Jul 12, 2021
750710c
Merge branch 'master' into feature/accessible-curve-type
mikedotexe Jul 12, 2021
4dd1189
Moved {json_types => types}/public_key.rs
ChaoticTempest Jul 13, 2021
033f665
Merge branch 'feature/accessible-curve-type' into feature/public-key-…
ChaoticTempest Jul 13, 2021
bb545d1
Remove commented code
ChaoticTempest Jul 13, 2021
4596634
Merge branch 'feature/public-key-as-base58-key' of https://github.com…
ChaoticTempest Jul 13, 2021
c890e40
Added deprecated CurveType export
ChaoticTempest Jul 13, 2021
190fee3
Cargo fmt
ChaoticTempest Jul 13, 2021
7094275
Fix typo
ChaoticTempest Jul 13, 2021
84baf0e
Update changelog
ChaoticTempest Jul 13, 2021
b5ee141
Merge pull request #464 from near/feature/public-key-as-base58-key
ChaoticTempest Jul 13, 2021
f897ce8
Merge branch 'master' into feature/accessible-curve-type
ChaoticTempest Jul 13, 2021
5a67860
Moved import out of the way
ChaoticTempest Jul 15, 2021
22cf090
Get rid of redundant from_parts call
ChaoticTempest Jul 15, 2021
b44932b
Merge branch 'master' of https://github.com/near/near-sdk-rs into fea…
ChaoticTempest Jul 15, 2021
54c46a1
Remove TryFrom<{&str, String}> for PublicKey
ChaoticTempest Jul 15, 2021
79736c3
Merge branch 'master' into feature/accessible-curve-type
ChaoticTempest Jul 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

156 changes: 110 additions & 46 deletions near-sdk/src/json_types/public_key.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
use borsh::{BorshDeserialize, BorshSerialize};
use borsh::{maybestd::io, BorshDeserialize, BorshSerialize};
austinabell marked this conversation as resolved.
Show resolved Hide resolved
use bs58::decode::Error as B58Error;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;

/// PublicKey curve
#[derive(
Debug, Clone, Copy, Serialize, Deserialize, PartialEq, BorshDeserialize, BorshSerialize,
)]
#[derive(Debug, Clone, Copy, PartialOrd, Ord, Eq, PartialEq, BorshDeserialize, BorshSerialize)]
#[repr(u8)]
pub enum CurveType {
ED25519 = 0,
SECP256K1 = 1,
}

impl TryFrom<u8> for CurveType {
type Error = ParsePublicKeyError;

fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::ED25519),
1 => Ok(Self::SECP256K1),
_ => Err(ParsePublicKeyError { kind: ParsePublicKeyErrorKind::UnknownCurve }),
}
}
}

ChaoticTempest marked this conversation as resolved.
Show resolved Hide resolved
impl TryFrom<String> for CurveType {
type Error = Box<dyn std::error::Error>;
type Error = ParsePublicKeyError;

fn try_from(value: String) -> Result<Self, Self::Error> {
Ok(value.parse::<Self>()?)
Expand Down Expand Up @@ -50,8 +60,11 @@ impl std::str::FromStr for CurveType {
/// .parse()
/// .unwrap();
/// ```
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, BorshDeserialize, BorshSerialize)]
pub struct Base58PublicKey(pub Vec<u8>);
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]
pub struct Base58PublicKey {
curve: CurveType,
data: Vec<u8>,
}

impl Base58PublicKey {
fn split_key_type_data(value: &str) -> Result<(CurveType, &str), ParsePublicKeyError> {
Expand All @@ -63,23 +76,45 @@ impl Base58PublicKey {
Ok((CurveType::ED25519, value))
}
}

fn from_parts(curve: CurveType, data: Vec<u8>) -> Result<Self, ParsePublicKeyError> {
let expected_length = match curve {
CurveType::ED25519 => 32,
CurveType::SECP256K1 => 64,
};
if data.len() != expected_length {
return Err(ParsePublicKeyError {
kind: ParsePublicKeyErrorKind::InvalidLength(data.len()),
});
}

Ok(Self { curve, data })
}

/// Get info about the CurveType for this public key
pub fn curve(&self) -> CurveType {
ChaoticTempest marked this conversation as resolved.
Show resolved Hide resolved
self.curve
}
}

impl From<Base58PublicKey> for Vec<u8> {
fn from(v: Base58PublicKey) -> Vec<u8> {
v.0
fn from(mut v: Base58PublicKey) -> Vec<u8> {
v.data.insert(0, v.curve as u8);
v.data
}
}

impl TryFrom<Vec<u8>> for Base58PublicKey {
type Error = Box<dyn std::error::Error>;
type Error = ParsePublicKeyError;

fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
match v.len() {
33 if v[0] == 0 => Ok(Self(v)),
65 if v[0] == 1 => Ok(Self(v)),
_ => Err("Invalid public key".into()),
fn try_from(mut data: Vec<u8>) -> Result<Self, Self::Error> {
if data.len() == 0 {
return Err(ParsePublicKeyError {
kind: ParsePublicKeyErrorKind::InvalidLength(data.len()),
});
}
let curve = CurveType::try_from(data.remove(0))?;
Self::from_parts(curve, data)
}
}

Expand All @@ -97,31 +132,34 @@ impl<'de> serde::Deserialize<'de> for Base58PublicKey {
where
D: serde::Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
let s: String = serde::Deserialize::deserialize(deserializer)?;
s.parse::<Base58PublicKey>().map_err(serde::de::Error::custom)
}
}

impl From<&Base58PublicKey> for String {
fn from(str_public_key: &Base58PublicKey) -> Self {
match str_public_key.0[0] {
0 => "ed25519:".to_string() + &bs58::encode(&str_public_key.0[1..]).into_string(),
1 => "secp256k1:".to_string() + &bs58::encode(&str_public_key.0[1..]).into_string(),
_ => panic!("Unexpected curve"),
match str_public_key.curve {
CurveType::ED25519 => {
["ed25519:", &bs58::encode(&str_public_key.data).into_string()].concat()
}
CurveType::SECP256K1 => {
["secp256k1:", &bs58::encode(&str_public_key.data).into_string()].concat()
}
}
ChaoticTempest marked this conversation as resolved.
Show resolved Hide resolved
}
}

impl TryFrom<String> for Base58PublicKey {
type Error = Box<dyn std::error::Error>;
type Error = ParsePublicKeyError;

fn try_from(value: String) -> Result<Self, Self::Error> {
Self::try_from(value.as_str())
}
}

impl TryFrom<&str> for Base58PublicKey {
type Error = Box<dyn std::error::Error>;
type Error = ParsePublicKeyError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(value.parse::<Self>()?)
Expand All @@ -132,24 +170,31 @@ impl std::str::FromStr for Base58PublicKey {
type Err = ParsePublicKeyError;

fn from_str(value: &str) -> Result<Self, Self::Err> {
let (key_type, key_data) = Base58PublicKey::split_key_type_data(&value)?;
let expected_length = match key_type {
let (curve, key_data) = Base58PublicKey::split_key_type_data(&value)?;
let data = bs58::decode(key_data).into_vec()?;
Self::from_parts(curve, data)
}
}

impl BorshDeserialize for Base58PublicKey {
fn deserialize(buf: &mut &[u8]) -> io::Result<Self> {
let buf = Vec::<u8>::deserialize(buf)?;
Self::try_from(buf).map_err(|err| io::Error::new(io::ErrorKind::Other, err))
}
}

impl BorshSerialize for Base58PublicKey {
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
let len = match self.curve {
CurveType::ED25519 => 32,
CurveType::SECP256K1 => 64,
};
let data = bs58::decode(key_data).into_vec()?;
if data.len() != expected_length {
return Err(ParsePublicKeyError {
kind: ParsePublicKeyErrorKind::InvalidLength(data.len()),
});
}
let mut res = Vec::with_capacity(1 + expected_length);
match key_type {
CurveType::ED25519 => res.push(0),
CurveType::SECP256K1 => res.push(1),
};
res.extend(data);
Ok(Self(res))

let mut data = Vec::with_capacity(1 + len);
data.push(self.curve as u8);
data.extend(&self.data);

BorshSerialize::serialize(&data, writer)
}
}

Expand Down Expand Up @@ -190,25 +235,25 @@ mod tests {
use super::*;
use std::convert::TryInto;

fn binary_key() -> Vec<u8> {
let mut binary_key = vec![0];
binary_key.extend(
fn expected_key() -> Base58PublicKey {
let mut key = vec![CurveType::ED25519 as u8];
key.extend(
bs58::decode("6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp").into_vec().unwrap(),
);
binary_key
key.try_into().unwrap()
}

#[test]
fn test_public_key_deser() {
let key: Base58PublicKey =
serde_json::from_str("\"ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp\"")
.unwrap();
assert_eq!(key.0, binary_key());
assert_eq!(key, expected_key());
}

#[test]
fn test_public_key_ser() {
let key: Base58PublicKey = binary_key().try_into().unwrap();
let key: Base58PublicKey = expected_key();
let actual: String = serde_json::to_string(&key).unwrap();
assert_eq!(actual, "\"ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp\"");
}
Expand All @@ -217,13 +262,32 @@ mod tests {
fn test_public_key_from_str() {
let key = Base58PublicKey::try_from("ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp")
.unwrap();
assert_eq!(key.0, binary_key());
assert_eq!(key, expected_key());
}

#[test]
fn test_public_key_to_string() {
let key: Base58PublicKey = binary_key().try_into().unwrap();
let key: Base58PublicKey = expected_key();
let actual: String = String::try_from(&key).unwrap();
assert_eq!(actual, "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp");
}

#[test]
fn test_public_key_borsh_format_change() {
// Original struct to reference Borsh serialization from
#[derive(BorshSerialize, BorshDeserialize)]
struct Base58PublicKeyRef(Vec<u8>);

let mut data = vec![CurveType::ED25519 as u8];
data.extend(
bs58::decode("6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp").into_vec().unwrap(),
);

// Test internal serialization of Vec<u8> is the same:
let old_key = Base58PublicKeyRef(data.clone());
let old_encoded_key = old_key.try_to_vec().unwrap();
let new_key: Base58PublicKey = data.try_into().unwrap();
let new_encoded_key = new_key.clone().try_to_vec().unwrap();
assert_eq!(old_encoded_key, new_encoded_key);
}
}