github.com/consensys/gnark-crypto@v0.14.0/accumulator/merkletree/readers.go (about)

     1  // Original Copyright (c) 2015 Nebulous
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  // The above copyright notice and this permission notice shall be included in all
    10  // copies or substantial portions of the Software.
    11  //
    12  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    13  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    14  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    15  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    16  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    17  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    18  // SOFTWARE.
    19  
    20  package merkletree
    21  
    22  import (
    23  	"errors"
    24  	"hash"
    25  	"io"
    26  )
    27  
    28  // ReadAll will read segments of size 'segmentSize' and push them into the tree
    29  // until EOF is reached. Success will return 'err == nil', not 'err == EOF'. No
    30  // padding is added to the data, so the last element may be smaller than
    31  // 'segmentSize'.
    32  func (t *Tree) ReadAll(r io.Reader, segmentSize int) error {
    33  	for {
    34  		segment := make([]byte, segmentSize)
    35  		n, readErr := io.ReadFull(r, segment)
    36  		if readErr == io.EOF {
    37  			// All data has been read.
    38  			break
    39  		} else if readErr == io.ErrUnexpectedEOF {
    40  			// This is the last segment, and there aren't enough bytes to fill
    41  			// the entire segment. Note that the next call will return io.EOF.
    42  			segment = segment[:n]
    43  		} else if readErr != nil {
    44  			return readErr
    45  		}
    46  		t.Push(segment)
    47  	}
    48  	return nil
    49  }
    50  
    51  // ReaderRoot returns the Merkle root of the data read from the reader, where
    52  // each leaf is 'segmentSize' long and 'h' is used as the hashing function. All
    53  // leaves will be 'segmentSize' bytes except the last leaf, which will not be
    54  // padded out if there are not enough bytes remaining in the reader.
    55  func ReaderRoot(r io.Reader, h hash.Hash, segmentSize int) (root []byte, err error) {
    56  	tree := New(h)
    57  	err = tree.ReadAll(r, segmentSize)
    58  	if err != nil {
    59  		return
    60  	}
    61  	root = tree.Root()
    62  	return
    63  }
    64  
    65  // BuildReaderProof returns a proof that certain data is in the merkle tree
    66  // created by the data in the reader. The merkle root, set of proofs, and the
    67  // number of leaves in the Merkle tree are all returned. All leaves will we
    68  // 'segmentSize' bytes except the last leaf, which will not be padded out if
    69  // there are not enough bytes remaining in the reader.
    70  func BuildReaderProof(r io.Reader, h hash.Hash, segmentSize int, index uint64) (root []byte, proofSet [][]byte, numLeaves uint64, err error) {
    71  	tree := New(h)
    72  	err = tree.SetIndex(index)
    73  	if err != nil {
    74  		// This code should be unreachable - SetIndex will only return an error
    75  		// if the tree is not empty, and yet the tree should be empty at this
    76  		// point.
    77  		panic(err)
    78  	}
    79  	err = tree.ReadAll(r, segmentSize)
    80  	if err != nil {
    81  		return
    82  	}
    83  	root, proofSet, _, numLeaves = tree.Prove()
    84  	if len(proofSet) == 0 {
    85  		err = errors.New("index was not reached while creating proof")
    86  		return
    87  	}
    88  	return
    89  }