add `FromStr` implementation for key types
This commit is contained in:
parent
dc2cd97196
commit
572adb2873
95
src/key.rs
95
src/key.rs
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
#[cfg(any(test, feature = "rand"))] use rand::Rng;
|
#[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 super::Error::{self, InvalidPublicKey, InvalidSecretKey};
|
||||||
use Signing;
|
use Signing;
|
||||||
use Verification;
|
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
|
/// The number 1 encoded as a secret key
|
||||||
/// Deprecated; `static` is not what I want; use `ONE_KEY` instead
|
/// Deprecated; `static` is not what I want; use `ONE_KEY` instead
|
||||||
pub static ONE: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0,
|
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"))]
|
#[cfg(any(test, feature = "rand"))]
|
||||||
fn random_32_bytes<R: Rng>(rng: &mut R) -> [u8; 32] {
|
fn random_32_bytes<R: Rng>(rng: &mut R) -> [u8; 32] {
|
||||||
let mut ret = [0u8; 32];
|
let mut ret = [0u8; 32];
|
||||||
|
@ -318,34 +349,22 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::super::{Secp256k1};
|
use Secp256k1;
|
||||||
|
use from_hex;
|
||||||
use super::super::Error::{InvalidPublicKey, InvalidSecretKey};
|
use super::super::Error::{InvalidPublicKey, InvalidSecretKey};
|
||||||
use super::{PublicKey, SecretKey};
|
use super::{PublicKey, SecretKey};
|
||||||
use super::super::constants;
|
use super::super::constants;
|
||||||
|
|
||||||
use rand::{Rng, thread_rng};
|
use rand::{Rng, thread_rng};
|
||||||
|
use std::iter;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
macro_rules! hex {
|
macro_rules! hex {
|
||||||
($hex:expr) => {
|
($hex:expr) => ({
|
||||||
{
|
let mut result = vec![0; $hex.len() / 2];
|
||||||
let mut vec = Vec::new();
|
from_hex($hex, &mut result).expect("valid hex string");
|
||||||
let mut b = 0;
|
result
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -482,10 +501,40 @@ mod test {
|
||||||
sk.to_string(),
|
sk.to_string(),
|
||||||
"01010101010101010001020304050607ffff0000ffff00006363636363636363"
|
"01010101010101010001020304050607ffff0000ffff00006363636363636363"
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
SecretKey::from_str("01010101010101010001020304050607ffff0000ffff00006363636363636363").unwrap(),
|
||||||
|
sk
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pk.to_string(),
|
pk.to_string(),
|
||||||
"0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"
|
"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]
|
#[test]
|
||||||
|
|
54
src/lib.rs
54
src/lib.rs
|
@ -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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use rand::{Rng, thread_rng};
|
use rand::{Rng, thread_rng};
|
||||||
|
|
||||||
use key::{SecretKey, PublicKey};
|
use key::{SecretKey, PublicKey};
|
||||||
|
use super::from_hex;
|
||||||
use super::constants;
|
use super::constants;
|
||||||
use super::{Secp256k1, Signature, RecoverableSignature, Message, RecoveryId};
|
use super::{Secp256k1, Signature, RecoverableSignature, Message, RecoveryId};
|
||||||
use super::Error::{InvalidMessage, IncorrectSignature, InvalidSignature};
|
use super::Error::{InvalidMessage, IncorrectSignature, InvalidSignature};
|
||||||
|
|
||||||
macro_rules! hex {
|
macro_rules! hex {
|
||||||
($hex:expr) => {
|
($hex:expr) => ({
|
||||||
{
|
let mut result = vec![0; $hex.len() / 2];
|
||||||
let mut vec = Vec::new();
|
from_hex($hex, &mut result).expect("valid hex string");
|
||||||
let mut b = 0;
|
result
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in New Issue