Merkle Tree create verification hashes and implementation of validation function. #48

This commit is contained in:
Kleissner
2021-11-27 02:30:31 +01:00
parent 19971c629d
commit c7665d7385
2 changed files with 73 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ In case of uneven number of fragments, the last fragment will be hashed against
package fragment
import (
"bytes"
"errors"
"io"
@@ -134,6 +135,56 @@ func calculateMiddleHash(hash1 []byte, hash2 []byte) (newHash []byte) {
return hash[:]
}
// CreateVerification returns the verification hashes for the given fragment number. The root hash itself is not included.
// The result might be empty if there is no or a single fragment.
// Each verification hash has a preceding left (= 0)/right (= 1) indicator that indicates where the verification is positioned.
// This makes the algorithm future proof, in case uneven leafs will be handled differently.
func (tree *MerkleTree) CreateVerification(fragment uint64) (verificationHashes [][]byte) {
// 0 fragments: Empty data.
// 1 fragment: The hash of the fragment is the root hash.
if tree.fragmentCount <= 1 {
return nil
} else if fragment >= tree.fragmentCount {
// invalid fragment index
return nil
}
// first hash it he neighbor fragment hash, if available
if fragment == tree.fragmentCount-1 && fragment%2 == 0 {
} else if fragment%2 == 0 {
verificationHashes = append(verificationHashes, append([]byte{1}, tree.fragmentHashes[fragment+1]...))
} else {
verificationHashes = append(verificationHashes, append([]byte{0}, tree.fragmentHashes[fragment-1]...))
}
// go through all middle hash levels
for n := 0; n < len(tree.middleHashes); n++ {
fragment = fragment / 2
if fragment == uint64(len(tree.middleHashes[n])-1) && fragment%2 == 0 {
} else if fragment%2 == 0 {
verificationHashes = append(verificationHashes, append([]byte{1}, tree.middleHashes[n][fragment+1]...))
} else {
verificationHashes = append(verificationHashes, append([]byte{0}, tree.middleHashes[n][fragment-1]...))
}
}
return
}
// MerkleVerify validates the hashed data against the verification hashes and the known root hash.
func MerkleVerify(rootHash []byte, dataHash []byte, verificationHashes [][]byte) (valid bool) {
for _, verifyHash := range verificationHashes {
if verifyHash[0] == 0 {
dataHash = calculateMiddleHash(verifyHash[1:], dataHash)
} else {
dataHash = calculateMiddleHash(dataHash, verifyHash[1:])
}
}
return bytes.Equal(rootHash, dataHash)
}
// Export/Import of the merkle tree structure:
// TODO

View File

@@ -7,6 +7,8 @@ import (
"fmt"
"io"
"testing"
"lukechampine.com/blake3"
)
func TestFragment0(t *testing.T) {
@@ -28,6 +30,26 @@ func TestFragment0(t *testing.T) {
}
printMerkleTree(tree)
// Validate all hashes.
for n := uint64(0); n < tree.fragmentCount; n++ {
verificationHashes := tree.CreateVerification(n)
dataSize := tree.fragmentSize
if n == tree.fragmentCount-1 {
dataSize = tree.fileSize - n*tree.fragmentSize
}
dataHash := blake3.Sum256(data[n*tree.fragmentSize : n*tree.fragmentSize+dataSize])
valid := MerkleVerify(tree.rootHash, dataHash[:], verificationHashes)
fmt.Printf("Validate fragment %d: %t\n", n, valid)
if !valid {
for m := 0; m < len(verificationHashes); m++ {
fmt.Printf("-> Middle hash [level %d]: %s\n", m-1, hex.EncodeToString(verificationHashes[m]))
}
}
}
}
func printMerkleTree(tree *MerkleTree) {