mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-17 02:47:51 +01:00
Merkle Tree create verification hashes and implementation of validation function. #48
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user