go-ethereum/nomt/core/hasher.go
weiihann 2db24e85a3 nomt/core: redesign for EIP-7864 compatibility (Phase A)
Replace Keccak256+MSB tagging with SHA256. Remove leaf nodes entirely,
replacing them with opaque stem hashes. Simplify NodeKind to just
Terminator and Internal. Add HashStem (8-level binary SHA256 tree
matching bintrie StemNode.Hash). Reduce max trie depth from 256 to 248
(31-byte stem path). Replace BuildTrie/LeafOp with
BuildInternalTree/StemKeyValue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 21:59:53 +08:00

62 lines
1.5 KiB
Go

package core
import "crypto/sha256"
const (
// StemSize is the number of bytes in a stem path (248 bits).
StemSize = 31
// StemNodeWidth is the number of value slots per stem node.
StemNodeWidth = 256
// HashSize is the size of a SHA256 hash in bytes.
HashSize = 32
)
// HashInternal computes SHA256(left || right) matching EIP-7864's InternalNode.Hash().
func HashInternal(data *InternalData) Node {
h := sha256.New()
h.Write(data.Left[:])
h.Write(data.Right[:])
var out Node
h.Sum(out[:0])
return out
}
// HashStem computes the stem node hash matching EIP-7864's StemNode.Hash().
//
// Algorithm:
// 1. SHA256 each non-nil value to get 256 leaf hashes (nil → zero hash)
// 2. Build an 8-level binary SHA256 tree (256 → 128 → ... → 1 root)
// Skip pairs where both children are zero (produce zero parent)
// 3. Final hash: SHA256(stem || 0x00 || subtreeRoot)
func HashStem(stem [StemSize]byte, values [StemNodeWidth][]byte) Node {
var data [StemNodeWidth]Node
for i, v := range values {
if v != nil {
data[i] = sha256.Sum256(v)
}
}
h := sha256.New()
for level := 1; level <= 8; level++ {
for i := range StemNodeWidth / (1 << level) {
if data[i*2] == (Node{}) && data[i*2+1] == (Node{}) {
data[i] = Node{}
continue
}
h.Reset()
h.Write(data[i*2][:])
h.Write(data[i*2+1][:])
h.Sum(data[i][:0])
}
}
h.Reset()
h.Write(stem[:])
h.Write([]byte{0x00})
h.Write(data[0][:])
var out Node
h.Sum(out[:0])
return out
}