103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
|
|
package chain
|
||
|
|
|
||
|
|
import (
|
||
|
|
"crypto/sha256"
|
||
|
|
"encoding/hex"
|
||
|
|
|
||
|
|
"basicstack.de/proofedmesh/services/verification-service/internal/canonical"
|
||
|
|
"basicstack.de/proofedmesh/services/verification-service/internal/dsse"
|
||
|
|
"basicstack.de/proofedmesh/services/verification-service/internal/tlog"
|
||
|
|
)
|
||
|
|
|
||
|
|
// memTree is a test-only Merkle tree mirroring the transparency-log's
|
||
|
|
// in-memory backend. It lives in the chain tests (not under internal/tlog)
|
||
|
|
// so the proof verifier under test does not share code with the proof
|
||
|
|
// producer.
|
||
|
|
type memTree struct {
|
||
|
|
leaves [][]byte
|
||
|
|
}
|
||
|
|
|
||
|
|
func (t *memTree) add(env dsse.Envelope) tlog.Entry {
|
||
|
|
leafBytes, _ := canonical.Marshal(env)
|
||
|
|
t.leaves = append(t.leaves, leafHash(leafBytes))
|
||
|
|
idx := int64(len(t.leaves) - 1)
|
||
|
|
hash := "sha256:" + canonical.SHA256Hex(leafBytes)
|
||
|
|
return tlog.Entry{
|
||
|
|
ContentHash: hash,
|
||
|
|
Envelope: env,
|
||
|
|
LogIndex: idx,
|
||
|
|
InclusionProof: tlog.InclusionProof{},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (t *memTree) refreshProofs(entries ...*tlog.Entry) {
|
||
|
|
root := merkleTreeHashT(t.leaves)
|
||
|
|
rootStr := "sha256:" + hex.EncodeToString(root)
|
||
|
|
for _, e := range entries {
|
||
|
|
path := auditPathT(t.leaves, int(e.LogIndex))
|
||
|
|
hashes := make([]string, 0, len(path))
|
||
|
|
for _, h := range path {
|
||
|
|
hashes = append(hashes, "sha256:"+hex.EncodeToString(h))
|
||
|
|
}
|
||
|
|
e.InclusionProof = tlog.InclusionProof{
|
||
|
|
TreeSize: int64(len(t.leaves)),
|
||
|
|
TreeRootHash: rootStr,
|
||
|
|
Hashes: hashes,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func leafHash(data []byte) []byte {
|
||
|
|
h := sha256.New()
|
||
|
|
h.Write([]byte{0x00})
|
||
|
|
h.Write(data)
|
||
|
|
return h.Sum(nil)
|
||
|
|
}
|
||
|
|
|
||
|
|
func nodeHashT(left, right []byte) []byte {
|
||
|
|
h := sha256.New()
|
||
|
|
h.Write([]byte{0x01})
|
||
|
|
h.Write(left)
|
||
|
|
h.Write(right)
|
||
|
|
return h.Sum(nil)
|
||
|
|
}
|
||
|
|
|
||
|
|
func merkleTreeHashT(leaves [][]byte) []byte {
|
||
|
|
switch len(leaves) {
|
||
|
|
case 0:
|
||
|
|
s := sha256.Sum256(nil)
|
||
|
|
return s[:]
|
||
|
|
case 1:
|
||
|
|
return append([]byte(nil), leaves[0]...)
|
||
|
|
}
|
||
|
|
k := largestPow2LessThanT(len(leaves))
|
||
|
|
return nodeHashT(merkleTreeHashT(leaves[:k]), merkleTreeHashT(leaves[k:]))
|
||
|
|
}
|
||
|
|
|
||
|
|
func auditPathT(leaves [][]byte, m int) [][]byte {
|
||
|
|
n := len(leaves)
|
||
|
|
if n <= 1 {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
k := largestPow2LessThanT(n)
|
||
|
|
if m < k {
|
||
|
|
return append(auditPathT(leaves[:k], m), merkleTreeHashT(leaves[k:]))
|
||
|
|
}
|
||
|
|
return append(auditPathT(leaves[k:], m-k), merkleTreeHashT(leaves[:k]))
|
||
|
|
}
|
||
|
|
|
||
|
|
func largestPow2LessThanT(n int) int {
|
||
|
|
k := 1
|
||
|
|
for k < n {
|
||
|
|
k <<= 1
|
||
|
|
}
|
||
|
|
return k >> 1
|
||
|
|
}
|
||
|
|
|
||
|
|
func seedBytes(s string) []byte { return []byte(s) }
|
||
|
|
|
||
|
|
func sha(b []byte) []byte {
|
||
|
|
s := sha256.Sum256(b)
|
||
|
|
return s[:]
|
||
|
|
}
|