github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/clone/internal/verify/verify.go (about) 1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package verify supports verification that the downloaded contents match 16 // the root hash commitment made in a log checkpoint. 17 package verify 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/golang/glog" 24 "github.com/google/trillian-examples/clone/logdb" 25 "github.com/transparency-dev/merkle/compact" 26 ) 27 28 // LeafHashFn returns the leaf hash (commitment) to the given preimage at the given log index. 29 type LeafHashFn func(index uint64, data []byte) []byte 30 31 // NewLogVerifier returns a LogVerifier which obtains raw leaves from `db`, and uses the given 32 // hash functions to construct a merkle tree. 33 func NewLogVerifier(db *logdb.Database, lh LeafHashFn, ih compact.HashFn) LogVerifier { 34 return LogVerifier{ 35 db: db, 36 lh: lh, 37 rf: &compact.RangeFactory{Hash: ih}, 38 } 39 } 40 41 // LogVerifier calculates the Merkle root of a log. 42 type LogVerifier struct { 43 db *logdb.Database 44 lh LeafHashFn 45 rf *compact.RangeFactory 46 } 47 48 // MerkleRoot calculates the Merkle root hash of its log at the given size. 49 func (v LogVerifier) MerkleRoot(ctx context.Context, size uint64) ([]byte, [][]byte, error) { 50 cr := v.rf.NewEmptyRange(0) 51 from := uint64(0) 52 53 if cpSize, _, crBs, err := v.db.GetLatestCheckpoint(ctx); err != nil { 54 if err != logdb.ErrNoDataFound { 55 return nil, nil, err 56 } 57 } else if size >= cpSize { 58 from = cpSize 59 cr, err = v.rf.NewRange(0, cpSize, crBs) 60 if err != nil { 61 return nil, nil, err 62 } 63 } 64 65 results := make(chan logdb.StreamResult, 1) 66 glog.V(1).Infof("Streaming leaves [%d, %d)", from, size) 67 go v.db.StreamLeaves(ctx, from, size, results) 68 69 index := from 70 for result := range results { 71 if result.Err != nil { 72 return nil, nil, fmt.Errorf("failed to get leaves from DB: %w", result.Err) 73 } 74 if err := cr.Append(v.lh(index, result.Leaf), nil); err != nil { 75 glog.Errorf("cr.Append(): %v", err) 76 } 77 index++ 78 } 79 if index != size { 80 return nil, nil, fmt.Errorf("expected to receive %d leaves but got %d", size, index) 81 } 82 root, err := cr.GetRootHash(nil) 83 return root, cr.Hashes(), err 84 }