use core::fmt;
use crate::constants::SECRET_KEY_SIZE;
use crate::ecdh::SharedSecret;
use crate::key::{Keypair, SecretKey};
use crate::musig::SessionSecretRand;
use crate::to_hex;
pub(crate) fn compare_array_eq_const<const N: usize>(a: &[u8; N], b: &[u8; N]) -> bool {
let accum = a.iter().zip(b.iter()).fold(0, |accum, (a, b)| accum | a ^ b);
unsafe { core::ptr::read_volatile(&accum) == 0 }
}
macro_rules! impl_display_secret {
($thing:ident) => {
impl ::core::fmt::Debug for $thing {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
use core::fmt;
use secp256k1_sys::secp256k1_ecdh_hash_function_default;
struct Hex16Writer([u8; 32]);
let mut output = Hex16Writer([0u8; 32]);
let secret = self.to_secret_bytes();
unsafe {
let ecdh_hash = secp256k1_ecdh_hash_function_default.unwrap();
assert!(secret.len() >= 32);
ecdh_hash(
output.0.as_mut_ptr(),
secret.as_ptr(),
"a debug-only byte 'y coordinate'".as_ptr(),
core::ptr::null_mut(),
);
}
impl fmt::Debug for Hex16Writer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for byte in self.0.iter().copied().take(8) {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
f.debug_tuple(stringify!($thing)).field(&output).finish()
}
}
};
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DisplaySecret {
secret: [u8; SECRET_KEY_SIZE],
}
impl_non_secure_erase!(DisplaySecret, secret, [0u8; SECRET_KEY_SIZE]);
impl fmt::Debug for DisplaySecret {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut slice = [0u8; SECRET_KEY_SIZE * 2];
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 byte in &self.secret {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
impl SecretKey {
#[inline]
pub fn display_secret(&self) -> DisplaySecret {
DisplaySecret { secret: self.to_secret_bytes() }
}
}
impl Keypair {
#[inline]
pub fn display_secret(&self) -> DisplaySecret {
DisplaySecret { secret: self.to_secret_bytes() }
}
}
impl SharedSecret {
#[inline]
pub fn display_secret(&self) -> DisplaySecret {
DisplaySecret { secret: self.to_secret_bytes() }
}
}
impl SessionSecretRand {
#[inline]
pub fn display_secret(&self) -> DisplaySecret {
DisplaySecret { secret: self.to_secret_bytes() }
}
}