Skip to main content

blockle_core/
hash.rs

1//! Hashing helpers.
2//!
3//! Block hashes are double-SHA256 over the serialized header (the convention
4//! Equihash ASICs and pool software assume). Everything else — txids, Merkle
5//! nodes, addresses — uses Blake2b-256 with a domain-separating
6//! personalization. Both are conservative against Grover-style quantum
7//! speedups at 256 bits.
8
9use blake2b_simd::Params;
10use sha2::{Digest, Sha256};
11
12pub type Hash32 = [u8; 32];
13
14/// Blake2b-256 with the given 16-byte-max personalization.
15pub fn blake2b_256_personal(personal: &[u8], data: &[u8]) -> Hash32 {
16    let mut out = [0u8; 32];
17    let hash = Params::new()
18        .hash_length(32)
19        .personal(personal)
20        .to_state()
21        .update(data)
22        .finalize();
23    out.copy_from_slice(hash.as_bytes());
24    out
25}
26
27/// General-purpose consensus hash (txids, sighashes).
28pub fn blake2b_256(data: &[u8]) -> Hash32 {
29    blake2b_256_personal(b"BlklHash", data)
30}
31
32/// Un-personalized Blake2b-256 — byte-identical to the VM's `BLAKE2B` opcode.
33/// Used to derive BLOCK-20 balance-storage keys (`H(0x01 ‖ address)`) from
34/// native code so the native AMM and the token contract share the same slots.
35pub fn blake2b_256_raw(data: &[u8]) -> Hash32 {
36    let mut out = [0u8; 32];
37    let hash = Params::new().hash_length(32).to_state().update(data).finalize();
38    out.copy_from_slice(hash.as_bytes());
39    out
40}
41
42/// Double-SHA256 — the block (header) hash.
43pub fn sha256d(data: &[u8]) -> Hash32 {
44    let first = Sha256::digest(data);
45    let second = Sha256::digest(first);
46    let mut out = [0u8; 32];
47    out.copy_from_slice(&second);
48    out
49}
50
51/// Address derivation: full Blake2b-256 of the public key. 32 bytes keeps a
52/// post-quantum security margin (Grover leaves ~128 bits of preimage
53/// resistance).
54pub fn address_hash(pubkey: &[u8]) -> [u8; 32] {
55    blake2b_256_personal(b"BlklAddr", pubkey)
56}
57
58/// Display convention for block hashes / txids: reversed hex, like Bitcoin,
59/// so low-target hashes show their leading zeros.
60pub fn display_hash(h: &Hash32) -> String {
61    let mut rev = *h;
62    rev.reverse();
63    hex::encode(rev)
64}