crate::ix!();
pub struct HashWriter {
ctx: Sha256,
n_type: i32,
n_version: i32,
}
impl<T> Shl<&T> for HashWriter
where
T: AsRef<[u8]> + ?Sized, {
type Output = HashWriter;
#[inline]
fn shl(mut self, rhs: &T) -> Self::Output {
self.write(rhs.as_ref());
self
}
}
impl HashWriter {
#[instrument(level = "trace")]
pub fn new(n_type_in: i32, n_version_in: i32) -> Self {
Self {
ctx: Sha256::new(),
n_type: n_type_in,
n_version: n_version_in,
}
}
#[inline]
pub fn get_type(&self) -> i32 {
self.n_type
}
#[inline]
pub fn get_version(&self) -> i32 {
self.n_version
}
#[instrument(level = "trace", skip(self, pch))]
pub fn write(&mut self, pch: &[u8]) {
self.ctx.write(pch);
}
#[instrument(level = "debug", skip(self))]
pub fn get_hash(&mut self) -> u256 {
let mut first = [0u8; 32];
self.ctx.finalize(&mut first);
self.ctx.reset();
self.ctx.write(&first);
let mut second = [0u8; 32];
self.ctx.finalize(&mut second);
u256::from_le_bytes(second)
}
#[instrument(level = "debug", skip(self))]
pub fn getsha256(&mut self) -> u256 {
let mut buf = [0u8; 32];
self.ctx.finalize(&mut buf);
u256::from_le_bytes(buf)
}
#[instrument(level = "trace", skip(self))]
pub fn get_cheap_hash(&mut self) -> u64 {
let digest = self.get_hash();
let mut tmp = [0u8; 8];
tmp.copy_from_slice(&<u256 as AsRef<[u8]>>::as_ref(&digest)[..8]);
u64::from_le_bytes(tmp)
}
}
pub fn tagged_hash(tag: &str) -> HashWriter {
let mut taghash = [0u8; 32];
let mut sha = Sha256::new();
sha.write(tag.as_bytes());
sha.finalize(&mut taghash);
let mut writer = HashWriter::new(SER_GETHASH as i32, 0);
writer.write(&taghash);
writer.write(&taghash);
writer
}
lazy_static!{
static ref HASHER_TAPSIGHASH: HashWriter = tagged_hash("TapSighash");
static ref HASHER_TAPLEAF: HashWriter = tagged_hash("TapLeaf");
static ref HASHER_TAPBRANCH: HashWriter = tagged_hash("TapBranch");
static ref HASHER_TAPTWEAK: HashWriter = tagged_hash("TapTweak");
}
#[cfg(test)]
mod writer_shl_spec {
use super::*;
#[traced_test]
fn shl_writes_bytes_and_preserves_type_version() {
let bytes = b"abc";
let writer = HashWriter::new(42, 17) << &bytes[..];
assert_eq!(writer.get_type(), 42);
assert_eq!(writer.get_version(), 17);
}
#[test]
fn constructing_tagged_hash_does_not_panic() {
let _ = tagged_hash("TapLeaf"); }
}