github.com/ethersphere/bee/v2@v2.2.0/pkg/bmt/proof.go (about) 1 // Copyright 2022 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bmt 6 7 // Prover wraps the Hasher to allow Merkle proof functionality 8 type Prover struct { 9 *Hasher 10 } 11 12 // Proof represents a Merkle proof of segment 13 type Proof struct { 14 ProveSegment []byte 15 ProofSegments [][]byte 16 Span []byte 17 Index int 18 } 19 20 // Hash overrides base hash function of Hasher to fill buffer with zeros until chunk length 21 func (p Prover) Hash(b []byte) ([]byte, error) { 22 for i := p.size; i < p.maxSize; i += len(zerosection) { 23 _, err := p.Hasher.Write(zerosection) 24 if err != nil { 25 return nil, err 26 } 27 } 28 return p.Hasher.Hash(b) 29 } 30 31 // Proof returns the inclusion proof of the i-th data segment 32 func (p Prover) Proof(i int) Proof { 33 index := i 34 35 if i < 0 || i > 127 { 36 panic("segment index can only lie between 0-127") 37 } 38 i = i / 2 39 n := p.bmt.leaves[i] 40 isLeft := n.isLeft 41 var sisters [][]byte 42 for n = n.parent; n != nil; n = n.parent { 43 sisters = append(sisters, n.getSister(isLeft)) 44 isLeft = n.isLeft 45 } 46 47 secsize := 2 * p.segmentSize 48 offset := i * secsize 49 section := make([]byte, secsize) 50 copy(section, p.bmt.buffer[offset:offset+secsize]) 51 segment, firstSegmentSister := section[:p.segmentSize], section[p.segmentSize:] 52 if index%2 != 0 { 53 segment, firstSegmentSister = firstSegmentSister, segment 54 } 55 sisters = append([][]byte{firstSegmentSister}, sisters...) 56 return Proof{segment, sisters, p.span, index} 57 } 58 59 // Verify returns the bmt hash obtained from the proof which can then be checked against 60 // the BMT hash of the chunk 61 func (p Prover) Verify(i int, proof Proof) (root []byte, err error) { 62 var section []byte 63 if i%2 == 0 { 64 section = append(append(section, proof.ProveSegment...), proof.ProofSegments[0]...) 65 } else { 66 section = append(append(section, proof.ProofSegments[0]...), proof.ProveSegment...) 67 } 68 i = i / 2 69 n := p.bmt.leaves[i] 70 hasher := p.hasher() 71 isLeft := n.isLeft 72 root, err = doHash(hasher, section) 73 if err != nil { 74 return nil, err 75 } 76 n = n.parent 77 78 for _, sister := range proof.ProofSegments[1:] { 79 if isLeft { 80 root, err = doHash(hasher, root, sister) 81 } else { 82 root, err = doHash(hasher, sister, root) 83 } 84 if err != nil { 85 return nil, err 86 } 87 isLeft = n.isLeft 88 n = n.parent 89 } 90 return doHash(hasher, proof.Span, root) 91 } 92 93 func (n *node) getSister(isLeft bool) []byte { 94 var src []byte 95 96 if isLeft { 97 src = n.right 98 } else { 99 src = n.left 100 } 101 102 buf := make([]byte, len(src)) 103 copy(buf, src) 104 return buf 105 }