PublicKey: add read_from method to be symmetric with write_into

This commit is contained in:
Andrew Poelstra 2021-01-03 16:12:47 +00:00
parent 3c1117305f
commit 92000bf51b
1 changed files with 68 additions and 0 deletions

View File

@ -109,6 +109,24 @@ impl PublicKey {
} }
} }
/// Read the public key from a reader
///
/// This internally reads the first byte before reading the rest, so
/// use of a `BufReader` is recommended.
pub fn read_from<R: io::Read>(mut reader: R) -> Result<Self, io::Error> {
let mut bytes = [0; 65];
reader.read_exact(&mut bytes[0..1])?;
let bytes = if bytes[0] < 4 {
&mut bytes[..33]
} else {
&mut bytes[..65]
};
reader.read_exact(&mut bytes[1..])?;
Self::from_slice(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}
/// Serialize the public key to bytes /// Serialize the public key to bytes
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = Vec::new(); let mut buf = Vec::new();
@ -378,6 +396,7 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey {
mod tests { mod tests {
use super::{PrivateKey, PublicKey}; use super::{PrivateKey, PublicKey};
use secp256k1::Secp256k1; use secp256k1::Secp256k1;
use std::io;
use std::str::FromStr; use std::str::FromStr;
use hashes::hex::ToHex; use hashes::hex::ToHex;
use network::constants::Network::Testnet; use network::constants::Network::Testnet;
@ -481,4 +500,53 @@ mod tests {
assert_tokens(&pk_u.compact(), &[Token::BorrowedBytes(&PK_BYTES_U[..])]); assert_tokens(&pk_u.compact(), &[Token::BorrowedBytes(&PK_BYTES_U[..])]);
assert_tokens(&pk_u.readable(), &[Token::BorrowedStr(PK_STR_U)]); assert_tokens(&pk_u.readable(), &[Token::BorrowedStr(PK_STR_U)]);
} }
fn random_key(mut seed: u8) -> PublicKey {
loop {
let mut data = [0; 65];
for byte in &mut data[..] {
*byte = seed;
// totally a rng
seed = seed.wrapping_mul(41).wrapping_add(43);
}
if data[0] % 2 == 0 {
data[0] = 4;
if let Ok(key) = PublicKey::from_slice(&data[..]) {
return key;
}
} else {
data[0] = 2 + (data[0] >> 7);
if let Ok(key) = PublicKey::from_slice(&data[..33]) {
return key;
}
}
}
}
#[test]
fn pubkey_read_write() {
const N_KEYS: usize = 20;
let keys: Vec<_> = (0..N_KEYS).map(|i| random_key(i as u8)).collect();
let mut v = vec![];
for k in &keys {
k.write_into(&mut v).expect("writing into vec");
}
let mut dec_keys = vec![];
let mut cursor = io::Cursor::new(&v);
for _ in 0..N_KEYS {
dec_keys.push(PublicKey::read_from(&mut cursor).expect("reading from vec"));
}
assert_eq!(keys, dec_keys);
// sanity checks
assert!(PublicKey::read_from(&mut cursor).is_err());
assert!(PublicKey::read_from(io::Cursor::new(&[])).is_err());
assert!(PublicKey::read_from(io::Cursor::new(&[0; 33][..])).is_err());
assert!(PublicKey::read_from(io::Cursor::new(&[2; 32][..])).is_err());
assert!(PublicKey::read_from(io::Cursor::new(&[0; 65][..])).is_err());
assert!(PublicKey::read_from(io::Cursor::new(&[4; 64][..])).is_err());
}
} }