Dedicated display_secret fn for secret-containing types
Debug-print secrets as tagged hashes Refactoring Display/Debug for secret values with display_secret
This commit is contained in:
parent
635a6ae441
commit
6810c2b547
38
src/key.rs
38
src/key.rs
|
@ -21,7 +21,7 @@ use core::{fmt, str};
|
||||||
|
|
||||||
use super::{from_hex, Secp256k1};
|
use super::{from_hex, Secp256k1};
|
||||||
use super::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey};
|
use super::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey};
|
||||||
use Signing;
|
use ::{Signing};
|
||||||
use Verification;
|
use Verification;
|
||||||
use constants;
|
use constants;
|
||||||
use ffi::{self, CPtr};
|
use ffi::{self, CPtr};
|
||||||
|
@ -29,22 +29,7 @@ use ffi::{self, CPtr};
|
||||||
/// Secret 256-bit key used as `x` in an ECDSA signature
|
/// Secret 256-bit key used as `x` in an ECDSA signature
|
||||||
pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]);
|
pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]);
|
||||||
impl_array_newtype!(SecretKey, u8, constants::SECRET_KEY_SIZE);
|
impl_array_newtype!(SecretKey, u8, constants::SECRET_KEY_SIZE);
|
||||||
impl_pretty_debug!(SecretKey);
|
impl_display_secret!(SecretKey);
|
||||||
|
|
||||||
impl fmt::LowerHex for SecretKey {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
for ch in &self.0[..] {
|
|
||||||
write!(f, "{:02x}", *ch)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for SecretKey {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
fmt::LowerHex::fmt(self, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl str::FromStr for SecretKey {
|
impl str::FromStr for SecretKey {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
@ -164,6 +149,12 @@ impl SecretKey {
|
||||||
SecretKey(sk)
|
SecretKey(sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialize the secret key as byte value
|
||||||
|
#[inline]
|
||||||
|
pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Negates one secret key.
|
/// Negates one secret key.
|
||||||
pub fn negate_assign(
|
pub fn negate_assign(
|
||||||
|
@ -233,7 +224,8 @@ impl SecretKey {
|
||||||
impl ::serde::Serialize for SecretKey {
|
impl ::serde::Serialize for SecretKey {
|
||||||
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
if s.is_human_readable() {
|
if s.is_human_readable() {
|
||||||
s.collect_str(self)
|
let mut buf = [0u8; 64];
|
||||||
|
s.serialize_str(::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
|
||||||
} else {
|
} else {
|
||||||
s.serialize_bytes(&self[..])
|
s.serialize_bytes(&self[..])
|
||||||
}
|
}
|
||||||
|
@ -516,7 +508,7 @@ impl Ord for PublicKey {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use Secp256k1;
|
use Secp256k1;
|
||||||
use from_hex;
|
use {from_hex, to_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;
|
||||||
|
@ -710,7 +702,11 @@ mod test {
|
||||||
let (sk, _) = s.generate_keypair(&mut DumbRng(0));
|
let (sk, _) = s.generate_keypair(&mut DumbRng(0));
|
||||||
|
|
||||||
assert_eq!(&format!("{:?}", sk),
|
assert_eq!(&format!("{:?}", sk),
|
||||||
"SecretKey(0100000000000000020000000000000003000000000000000400000000000000)");
|
"SecretKey(#d3e0c51a23169bb5)");
|
||||||
|
|
||||||
|
let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2];
|
||||||
|
assert_eq!(to_hex(&sk[..], &mut buf).unwrap(),
|
||||||
|
"0100000000000000020000000000000003000000000000000400000000000000");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -733,7 +729,7 @@ mod test {
|
||||||
let pk = PublicKey::from_slice(&[0x02, 0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66]).expect("pk");
|
let pk = PublicKey::from_slice(&[0x02, 0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66]).expect("pk");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sk.to_string(),
|
sk.display_secret().to_string(),
|
||||||
"01010101010101010001020304050607ffff0000ffff00006363636363636363"
|
"01010101010101010001020304050607ffff0000ffff00006363636363636363"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -140,6 +140,8 @@ pub use secp256k1_sys as ffi;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
#[macro_use]
|
||||||
|
mod secret;
|
||||||
mod context;
|
mod context;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod ecdh;
|
pub mod ecdh;
|
||||||
|
@ -851,8 +853,8 @@ fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Utility function used to encode hex into a target u8 buffer. Returns
|
/// Utility function used to encode hex into a target u8 buffer. Returns
|
||||||
/// a reference to the target buffer as an str.
|
/// a reference to the target buffer as an str. Returns an error if the target
|
||||||
// it returns an error if the target buffer isn't big enough
|
/// buffer isn't big enough.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()> {
|
fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()> {
|
||||||
let hex_len = src.len() * 2;
|
let hex_len = src.len() * 2;
|
||||||
|
|
|
@ -18,10 +18,10 @@ macro_rules! impl_pretty_debug {
|
||||||
impl ::core::fmt::Debug for $thing {
|
impl ::core::fmt::Debug for $thing {
|
||||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
write!(f, "{}(", stringify!($thing))?;
|
write!(f, "{}(", stringify!($thing))?;
|
||||||
for i in self[..].iter().cloned() {
|
for i in &self[..] {
|
||||||
write!(f, "{:02x}", i)?;
|
write!(f, "{:02x}", i)?;
|
||||||
}
|
}
|
||||||
write!(f, ")")
|
f.write_str(")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,8 +76,9 @@ impl str::FromStr for Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opaque data structure that holds a keypair consisting of a secret and a public key.
|
/// Opaque data structure that holds a keypair consisting of a secret and a public key.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
|
#[derive(Clone)]
|
||||||
pub struct KeyPair(ffi::KeyPair);
|
pub struct KeyPair(ffi::KeyPair);
|
||||||
|
impl_display_secret!(KeyPair);
|
||||||
|
|
||||||
/// A Schnorr public key, used for verification of Schnorr signatures
|
/// A Schnorr public key, used for verification of Schnorr signatures
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
// Bitcoin secp256k1 bindings
|
||||||
|
// Written in 2021 by
|
||||||
|
// Maxim Orlovsky <orlovsky@pandoracore.com>
|
||||||
|
//
|
||||||
|
// To the extent possible under law, the author(s) have dedicated all
|
||||||
|
// copyright and related and neighboring rights to this software to
|
||||||
|
// the public domain worldwide. This software is distributed without
|
||||||
|
// any warranty.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the CC0 Public Domain Dedication
|
||||||
|
// along with this software.
|
||||||
|
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
//! Helpers for displaying secret values
|
||||||
|
|
||||||
|
use ::core::fmt;
|
||||||
|
use ::{SecretKey, schnorrsig::KeyPair, to_hex};
|
||||||
|
use constants::SECRET_KEY_SIZE;
|
||||||
|
|
||||||
|
macro_rules! impl_display_secret {
|
||||||
|
// Default hasher exists only in standard library and not alloc
|
||||||
|
($thing:ident) => {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl ::core::fmt::Debug for $thing {
|
||||||
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
|
use ::core::hash::Hasher;
|
||||||
|
const DEBUG_HASH_TAG: &[u8] = &[
|
||||||
|
0x66, 0xa6, 0x77, 0x1b, 0x9b, 0x6d, 0xae, 0xa1, 0xb2, 0xee, 0x4e, 0x07, 0x49,
|
||||||
|
0x4a, 0xac, 0x87, 0xa9, 0xb8, 0x5b, 0x4b, 0x35, 0x02, 0xaa, 0x6d, 0x0f, 0x79,
|
||||||
|
0xcb, 0x63, 0xe6, 0xf8, 0x66, 0x22
|
||||||
|
]; // =SHA256(b"rust-secp256k1DEBUG");
|
||||||
|
|
||||||
|
let mut hasher = ::std::collections::hash_map::DefaultHasher::new();
|
||||||
|
|
||||||
|
hasher.write(DEBUG_HASH_TAG);
|
||||||
|
hasher.write(DEBUG_HASH_TAG);
|
||||||
|
hasher.write(&self.serialize_secret());
|
||||||
|
let hash = hasher.finish();
|
||||||
|
|
||||||
|
f.debug_tuple(stringify!($thing))
|
||||||
|
.field(&format_args!("#{:016x}", hash))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper struct for safely printing secrets (like [`SecretKey`] value).
|
||||||
|
/// Formats the explicit byte value of the secret kept inside the type as a
|
||||||
|
/// little-endian hexadecimal string using the provided formatter.
|
||||||
|
///
|
||||||
|
/// Secrets should not implement neither [`Debug`] and [`Display`] traits directly,
|
||||||
|
/// and instead provide `fn display_secret<'a>(&'a self) -> DisplaySecret<'a>`
|
||||||
|
/// function to be used in different display contexts (see "examples" below).
|
||||||
|
///
|
||||||
|
/// [`Display`]: fmt::Display
|
||||||
|
/// [`Debug`]: fmt::Debug
|
||||||
|
pub struct DisplaySecret {
|
||||||
|
secret: [u8; SECRET_KEY_SIZE]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for DisplaySecret {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut slice = [0u8; 64];
|
||||||
|
let hex = to_hex(&self.secret, &mut slice).expect("fixed-size hex serializer failed");
|
||||||
|
f.debug_tuple("DisplaySecret")
|
||||||
|
.field(&hex)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DisplaySecret {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
for i in &self.secret {
|
||||||
|
write!(f, "{:02x}", i)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SecretKey {
|
||||||
|
/// Formats the explicit byte value of the secret key kept inside the type as a
|
||||||
|
/// little-endian hexadecimal string using the provided formatter.
|
||||||
|
///
|
||||||
|
/// This is the only method that outputs the actual secret key value, and, thus,
|
||||||
|
/// should be used with extreme precaution.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use secp256k1::key::ONE_KEY;
|
||||||
|
/// let key = ONE_KEY;
|
||||||
|
/// // Normal display hides value
|
||||||
|
/// assert_eq!(
|
||||||
|
/// "SecretKey(#2518682f7819fb2d)",
|
||||||
|
/// format!("{:?}", key)
|
||||||
|
/// );
|
||||||
|
/// // Here we explicitly display the secret value:
|
||||||
|
/// assert_eq!(
|
||||||
|
/// "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
/// format!("{}", key.display_secret())
|
||||||
|
/// );
|
||||||
|
/// assert_eq!(
|
||||||
|
/// "DisplaySecret(\"0000000000000000000000000000000000000000000000000000000000000001\")",
|
||||||
|
/// format!("{:?}", key.display_secret())
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn display_secret(&self) -> DisplaySecret {
|
||||||
|
DisplaySecret { secret: self.serialize_secret() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyPair {
|
||||||
|
/// Formats the explicit byte value of the secret key kept inside the type as a
|
||||||
|
/// little-endian hexadecimal string using the provided formatter.
|
||||||
|
///
|
||||||
|
/// This is the only method that outputs the actual secret key value, and, thus,
|
||||||
|
/// should be used with extreme precaution.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use secp256k1::key::ONE_KEY;
|
||||||
|
/// use secp256k1::schnorrsig::KeyPair;
|
||||||
|
/// use secp256k1::Secp256k1;
|
||||||
|
///
|
||||||
|
/// let secp = Secp256k1::new();
|
||||||
|
/// let key = ONE_KEY;
|
||||||
|
/// let key = KeyPair::from_secret_key(&secp, key);
|
||||||
|
///
|
||||||
|
/// // Normal display hides value
|
||||||
|
/// assert_eq!(
|
||||||
|
/// "KeyPair(#2518682f7819fb2d)",
|
||||||
|
/// format!("{:?}", key)
|
||||||
|
/// );
|
||||||
|
/// // Here we explicitly display the secret value:
|
||||||
|
/// assert_eq!(
|
||||||
|
/// "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
/// format!("{}", key.display_secret())
|
||||||
|
/// );
|
||||||
|
/// assert_eq!(
|
||||||
|
/// "DisplaySecret(\"0000000000000000000000000000000000000000000000000000000000000001\")",
|
||||||
|
/// format!("{:?}", key.display_secret())
|
||||||
|
/// );
|
||||||
|
#[inline]
|
||||||
|
pub fn display_secret(&self) -> DisplaySecret {
|
||||||
|
DisplaySecret { secret: self.serialize_secret() }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue