Skip to content
This repository has been archived by the owner on Jun 11, 2022. It is now read-only.

Commit

Permalink
Merge pull request #689 from input-output-hk/rest_account
Browse files Browse the repository at this point in the history
Add ability of decoding PublicKey from hex
  • Loading branch information
NicolasDP committed May 15, 2019
2 parents 740f972 + 5ffc4e8 commit c22ee2b
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 23 deletions.
77 changes: 54 additions & 23 deletions chain-crypto/src/hex.rs
Expand Up @@ -24,6 +24,8 @@ pub enum DecodeError {
/// A character was encountered is not part of the supported
/// hexadecimal alphabet. Contains the index of the faulty byte.
InvalidHexChar(usize),
/// Length of hex string is not even. Last character doesn't have a pair to encode a whole byte.
UnevenHexLength(usize),
}

impl fmt::Display for DecodeError {
Expand All @@ -32,6 +34,9 @@ impl fmt::Display for DecodeError {
DecodeError::InvalidHexChar(idx) => {
write!(f, "Non-hexadecimal character at byte index {}", idx)
}
DecodeError::UnevenHexLength(len) => {
write!(f, "Hex has uneven number of characters {}", len)
}
}
}
}
Expand Down Expand Up @@ -69,42 +74,68 @@ fn decode_bytes(input: &[u8]) -> Result<Vec<u8>, DecodeError> {
b.push(buf);
}
}

Ok(b)
match modulus {
0 => Ok(b),
_ => Err(DecodeError::UnevenHexLength(b.len() * 2 + 1)),
}
}

#[cfg(test)]
mod tests {
fn encode<D: AsRef<[u8]>>(input: D, expected: &str) {
let encoded = super::encode(input);
assert_eq!(encoded, expected);
}
fn decode<S: AsRef<[u8]>>(expected: &[u8], input: S) {
let decoded = super::decode(input).unwrap();
assert_eq!(decoded.as_slice(), expected);
use super::*;

fn assert_decode(input: impl AsRef<[u8]>, expected: impl AsRef<[u8]>) {
let result = decode(&input);

let input_str = format!("{:?}", input.as_ref());
let actual = result.expect(&format!("Failed to decode '{}'", input_str));
assert_eq!(
actual,
expected.as_ref(),
"Decoded invalid data from '{}'",
input_str
);
}

#[test]
fn test_vector_1() {
encode(&[1, 2, 3, 4], "01020304");
decode(&[1, 2, 3, 4], "01020304");
fn refute_decode(input: impl AsRef<[u8]>, expected: DecodeError) {
let result = decode(&input);

let input_str = format!("{:?}", input.as_ref());
let actual = result.expect_err(&format!("Did not fail to decode '{}'", input_str));
assert_eq!(
actual, expected,
"Invalid error when decoding '{}'",
input_str
);
}

#[test]
fn test_vector_2() {
encode(&[0xff, 0x0f, 0xff, 0xff], "ff0fffff");
decode(&[0xff, 0x0f, 0xff, 0xff], "ff0fffff");
fn test_decode() {
assert_decode("01020304", [0x01, 0x02, 0x03, 0x04]);
assert_decode(b"01020304", [0x01, 0x02, 0x03, 0x04]);
assert_decode("0123456789", [0x01, 0x23, 0x45, 0x67, 0x89]);
assert_decode("abcdef", [0xAB, 0xCD, 0xEF]);
assert_decode("ABCDEF", [0xAB, 0xCD, 0xEF]);
assert_decode(" 0\t\r102 \n", [0x01, 0x02]);
refute_decode("010x0304", DecodeError::InvalidHexChar(3));
refute_decode("0102030", DecodeError::UnevenHexLength(7));
}

#[test]
fn test_bytes() {
encode(&[1, 2, 3, 4], "01020304");
decode(&[1, 2, 3, 4], b"01020304");
fn assert_encode(input: impl AsRef<[u8]>, expected: &str) {
let actual = encode(&input);

assert_eq!(
actual,
expected,
"Invalid output for input {:?}",
input.as_ref()
);
}

#[test]
fn test_string() {
encode("1234", "31323334");
decode(&[1, 2, 3, 4], "01020304");
fn test_encode() {
assert_encode([0x01, 0x02, 0x03, 0x04], "01020304");
assert_encode([0x01, 0x23, 0x45, 0x67, 0x89], "0123456789");
assert_encode([0xAB, 0xCD, 0xEF], "abcdef");
}
}
39 changes: 39 additions & 0 deletions chain-crypto/src/key.rs
Expand Up @@ -3,6 +3,7 @@ use crate::hex;
use rand::{CryptoRng, RngCore};
use std::fmt;
use std::hash::Hash;
use std::str::FromStr;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SecretKeyError {
Expand All @@ -16,6 +17,12 @@ pub enum PublicKeyError {
StructureInvalid,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PublicKeyFromStrError {
HexMalformed(hex::DecodeError),
KeyInvalid(PublicKeyError),
}

pub trait AsymmetricKey {
type Secret: AsRef<[u8]> + Clone;
type Public: AsRef<[u8]> + Clone + PartialEq + Eq + Hash;
Expand Down Expand Up @@ -75,6 +82,16 @@ impl<A: AsymmetricKey> fmt::Display for PublicKey<A> {
write!(f, "{}", hex::encode(self.0.as_ref()))
}
}

impl<A: AsymmetricKey> FromStr for PublicKey<A> {
type Err = PublicKeyFromStrError;

fn from_str(hex: &str) -> Result<Self, Self::Err> {
let bytes = hex::decode(hex).map_err(PublicKeyFromStrError::HexMalformed)?;
Self::from_binary(&bytes).map_err(PublicKeyFromStrError::KeyInvalid)
}
}

impl fmt::Display for SecretKeyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand All @@ -83,6 +100,7 @@ impl fmt::Display for SecretKeyError {
}
}
}

impl fmt::Display for PublicKeyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand All @@ -91,9 +109,30 @@ impl fmt::Display for PublicKeyError {
}
}
}

impl fmt::Display for PublicKeyFromStrError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PublicKeyFromStrError::HexMalformed(_) => "hex encoding malformed",
PublicKeyFromStrError::KeyInvalid(_) => "invalid public key data",
}
.fmt(f)
}
}

impl std::error::Error for SecretKeyError {}

impl std::error::Error for PublicKeyError {}

impl std::error::Error for PublicKeyFromStrError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
PublicKeyFromStrError::HexMalformed(e) => Some(e),
PublicKeyFromStrError::KeyInvalid(e) => Some(e),
}
}
}

impl<A: AsymmetricKey> AsRef<[u8]> for PublicKey<A> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
Expand Down

0 comments on commit c22ee2b

Please sign in to comment.