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  }