add `FromStr` implementation for key types

This commit is contained in:
Andrew Poelstra 2018-08-26 18:39:41 +00:00
parent dc2cd97196
commit 572adb2873
2 changed files with 106 additions and 43 deletions

View File

@ -17,9 +17,9 @@
#[cfg(any(test, feature = "rand"))] use rand::Rng;
use std::{fmt, mem};
use std::{fmt, mem, str};
use super::{Secp256k1};
use super::{from_hex, Secp256k1};
use super::Error::{self, InvalidPublicKey, InvalidSecretKey};
use Signing;
use Verification;
@ -40,6 +40,17 @@ impl fmt::Display for SecretKey {
}
}
impl str::FromStr for SecretKey {
type Err = Error;
fn from_str(s: &str) -> Result<SecretKey, Error> {
let mut res = [0; constants::SECRET_KEY_SIZE];
match from_hex(s, &mut res) {
Ok(constants::SECRET_KEY_SIZE) => Ok(SecretKey(res)),
_ => Err(Error::InvalidSecretKey)
}
}
}
/// The number 1 encoded as a secret key
/// Deprecated; `static` is not what I want; use `ONE_KEY` instead
pub static ONE: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0,
@ -73,6 +84,26 @@ impl fmt::Display for PublicKey {
}
}
impl str::FromStr for PublicKey {
type Err = Error;
fn from_str(s: &str) -> Result<PublicKey, Error> {
let secp = Secp256k1::without_caps();
let mut res = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE];
match from_hex(s, &mut res) {
Ok(constants::PUBLIC_KEY_SIZE) => {
PublicKey::from_slice(
&secp,
&res[0..constants::PUBLIC_KEY_SIZE]
)
}
Ok(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE) => {
PublicKey::from_slice(&secp, &res)
}
_ => Err(Error::InvalidPublicKey)
}
}
}
#[cfg(any(test, feature = "rand"))]
fn random_32_bytes<R: Rng>(rng: &mut R) -> [u8; 32] {
let mut ret = [0u8; 32];
@ -318,34 +349,22 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey {
#[cfg(test)]
mod test {
use super::super::{Secp256k1};
use Secp256k1;
use from_hex;
use super::super::Error::{InvalidPublicKey, InvalidSecretKey};
use super::{PublicKey, SecretKey};
use super::super::constants;
use rand::{Rng, thread_rng};
use std::iter;
use std::str::FromStr;
macro_rules! hex {
($hex:expr) => {
{
let mut vec = Vec::new();
let mut b = 0;
for (idx, c) in $hex.as_bytes().iter().enumerate() {
b <<= 4;
match *c {
b'A'...b'F' => b |= c - b'A' + 10,
b'a'...b'f' => b |= c - b'a' + 10,
b'0'...b'9' => b |= c - b'0',
_ => panic!("Bad hex"),
}
if (idx & 1) == 1 {
vec.push(b);
b = 0;
}
}
vec
}
}
($hex:expr) => ({
let mut result = vec![0; $hex.len() / 2];
from_hex($hex, &mut result).expect("valid hex string");
result
});
}
#[test]
@ -482,10 +501,40 @@ mod test {
sk.to_string(),
"01010101010101010001020304050607ffff0000ffff00006363636363636363"
);
assert_eq!(
SecretKey::from_str("01010101010101010001020304050607ffff0000ffff00006363636363636363").unwrap(),
sk
);
assert_eq!(
pk.to_string(),
"0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"
);
assert_eq!(
PublicKey::from_str("0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166").unwrap(),
pk
);
assert_eq!(
PublicKey::from_str("04\
18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\
84B84DB303A340CD7D6823EE88174747D12A67D2F8F2F9BA40846EE5EE7A44F6"
).unwrap(),
pk
);
assert!(SecretKey::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").is_err());
assert!(SecretKey::from_str("01010101010101010001020304050607ffff0000ffff0000636363636363636363").is_err());
assert!(SecretKey::from_str("01010101010101010001020304050607ffff0000ffff0000636363636363636").is_err());
assert!(SecretKey::from_str("01010101010101010001020304050607ffff0000ffff000063636363636363").is_err());
assert!(SecretKey::from_str("01010101010101010001020304050607ffff0000ffff000063636363636363xx").is_err());
assert!(PublicKey::from_str("0300000000000000000000000000000000000000000000000000000000000000000").is_err());
assert!(PublicKey::from_str("0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16601").is_err());
assert!(PublicKey::from_str("0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16").is_err());
assert!(PublicKey::from_str("0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1").is_err());
assert!(PublicKey::from_str("xx0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1").is_err());
let long_str: String = iter::repeat('a').take(1024 * 1024).collect();
assert!(SecretKey::from_str(&long_str).is_err());
assert!(PublicKey::from_str(&long_str).is_err());
}
#[test]

View File

@ -708,36 +708,50 @@ impl<C: Verification> Secp256k1<C> {
}
}
/// Utility function used to parse hex into a target u8 buffer. Returns
/// the number of bytes converted or an error if it encounters an invalid
/// character or unexpected end of string.
fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
if hex.len() % 2 == 1 || hex.len() > target.len() * 2 {
return Err(());
}
let mut b = 0;
let mut idx = 0;
for c in hex.bytes() {
b <<= 4;
match c {
b'A'...b'F' => b |= c - b'A' + 10,
b'a'...b'f' => b |= c - b'a' + 10,
b'0'...b'9' => b |= c - b'0',
_ => return Err(()),
}
if (idx & 1) == 1 {
target[idx / 2] = b;
b = 0;
}
idx += 1;
}
Ok(idx / 2)
}
#[cfg(test)]
mod tests {
use rand::{Rng, thread_rng};
use key::{SecretKey, PublicKey};
use super::from_hex;
use super::constants;
use super::{Secp256k1, Signature, RecoverableSignature, Message, RecoveryId};
use super::Error::{InvalidMessage, IncorrectSignature, InvalidSignature};
macro_rules! hex {
($hex:expr) => {
{
let mut vec = Vec::new();
let mut b = 0;
for (idx, c) in $hex.as_bytes().iter().enumerate() {
b <<= 4;
match *c {
b'A'...b'F' => b |= c - b'A' + 10,
b'a'...b'f' => b |= c - b'a' + 10,
b'0'...b'9' => b |= c - b'0',
_ => panic!("Bad hex"),
}
if (idx & 1) == 1 {
vec.push(b);
b = 0;
}
}
vec
}
}
($hex:expr) => ({
let mut result = vec![0; $hex.len() / 2];
from_hex($hex, &mut result).expect("valid hex string");
result
});
}
#[test]