Merge pull request #241 from apoelstra/2019-03-pubkey-string
key: implement ToString and FromStr for PublicKey
This commit is contained in:
commit
7e1a6a4ab7
|
@ -37,6 +37,8 @@ use bitcoin_hashes::{hash160, sha256, Hash};
|
||||||
#[cfg(feature="bitcoinconsensus")] use std::convert;
|
#[cfg(feature="bitcoinconsensus")] use std::convert;
|
||||||
#[cfg(feature="bitcoinconsensus")] use bitcoin_hashes::sha256d;
|
#[cfg(feature="bitcoinconsensus")] use bitcoin_hashes::sha256d;
|
||||||
|
|
||||||
|
use util::key::PublicKey;
|
||||||
|
|
||||||
#[derive(Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
#[derive(Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||||
/// A Bitcoin script
|
/// A Bitcoin script
|
||||||
pub struct Script(Box<[u8]>);
|
pub struct Script(Box<[u8]>);
|
||||||
|
@ -599,6 +601,15 @@ impl Builder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pushes a public key
|
||||||
|
pub fn push_key(self, key: &PublicKey) -> Builder {
|
||||||
|
if key.compressed {
|
||||||
|
self.push_slice(&key.key.serialize()[..])
|
||||||
|
} else {
|
||||||
|
self.push_slice(&key.key.serialize_uncompressed()[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a single opcode to the script
|
/// Adds a single opcode to the script
|
||||||
pub fn push_opcode(mut self, data: opcodes::All) -> Builder {
|
pub fn push_opcode(mut self, data: opcodes::All) -> Builder {
|
||||||
self.0.push(data.into_u8());
|
self.0.push(data.into_u8());
|
||||||
|
@ -694,6 +705,7 @@ impl<D: Decoder> Decodable<D> for Script {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use std::str::FromStr;
|
||||||
use hex::decode as hex_decode;
|
use hex::decode as hex_decode;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -701,6 +713,7 @@ mod test {
|
||||||
|
|
||||||
use consensus::encode::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
|
use util::key::PublicKey;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn script() {
|
fn script() {
|
||||||
|
@ -725,6 +738,14 @@ mod test {
|
||||||
// data
|
// data
|
||||||
script = script.push_slice("NRA4VR".as_bytes()); comp.extend([6u8, 78, 82, 65, 52, 86, 82].iter().cloned()); assert_eq!(&script[..], &comp[..]);
|
script = script.push_slice("NRA4VR".as_bytes()); comp.extend([6u8, 78, 82, 65, 52, 86, 82].iter().cloned()); assert_eq!(&script[..], &comp[..]);
|
||||||
|
|
||||||
|
// keys
|
||||||
|
let keystr = "21032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af";
|
||||||
|
let key = PublicKey::from_str(&keystr[2..]).unwrap();
|
||||||
|
script = script.push_key(&key); comp.extend(hex_decode(keystr).unwrap().iter().cloned()); assert_eq!(&script[..], &comp[..]);
|
||||||
|
let keystr = "41042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133";
|
||||||
|
let key = PublicKey::from_str(&keystr[2..]).unwrap();
|
||||||
|
script = script.push_key(&key); comp.extend(hex_decode(keystr).unwrap().iter().cloned()); assert_eq!(&script[..], &comp[..]);
|
||||||
|
|
||||||
// opcodes
|
// opcodes
|
||||||
script = script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(&script[..], &comp[..]);
|
script = script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(&script[..], &comp[..]);
|
||||||
script = script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(&script[..], &comp[..]);
|
script = script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(&script[..], &comp[..]);
|
||||||
|
|
|
@ -64,6 +64,32 @@ impl PublicKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PublicKey {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.compressed {
|
||||||
|
for ch in &self.key.serialize()[..] {
|
||||||
|
write!(f, "{:02x}", ch)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for ch in &self.key.serialize_uncompressed()[..] {
|
||||||
|
write!(f, "{:02x}", ch)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for PublicKey {
|
||||||
|
type Err = encode::Error;
|
||||||
|
fn from_str(s: &str) -> Result<PublicKey, encode::Error> {
|
||||||
|
let key = secp256k1::PublicKey::from_str(s)?;
|
||||||
|
Ok(PublicKey {
|
||||||
|
key: key,
|
||||||
|
compressed: s.len() == 66
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
/// A Bitcoin ECDSA private key
|
/// A Bitcoin ECDSA private key
|
||||||
pub struct PrivateKey {
|
pub struct PrivateKey {
|
||||||
|
@ -161,7 +187,7 @@ impl ops::Index<ops::RangeFull> for PrivateKey {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::PrivateKey;
|
use super::{PrivateKey, PublicKey};
|
||||||
use secp256k1::Secp256k1;
|
use secp256k1::Secp256k1;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use network::constants::Network::Testnet;
|
use network::constants::Network::Testnet;
|
||||||
|
@ -193,7 +219,14 @@ mod tests {
|
||||||
assert_eq!(&sk.to_wif(), "5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3");
|
assert_eq!(&sk.to_wif(), "5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3");
|
||||||
|
|
||||||
let secp = Secp256k1::new();
|
let secp = Secp256k1::new();
|
||||||
let pk = Address::p2pkh(&sk.public_key(&secp), sk.network);
|
let mut pk = sk.public_key(&secp);
|
||||||
assert_eq!(&pk.to_string(), "1GhQvF6dL8xa6wBxLnWmHcQsurx9RxiMc8");
|
assert_eq!(pk.compressed, false);
|
||||||
|
assert_eq!(&pk.to_string(), "042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133");
|
||||||
|
assert_eq!(pk, PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap());
|
||||||
|
let addr = Address::p2pkh(&pk, sk.network);
|
||||||
|
assert_eq!(&addr.to_string(), "1GhQvF6dL8xa6wBxLnWmHcQsurx9RxiMc8");
|
||||||
|
pk.compressed = true;
|
||||||
|
assert_eq!(&pk.to_string(), "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af");
|
||||||
|
assert_eq!(pk, PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue