github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/merkle/map_verifier.go (about) 1 // Copyright 2016 Google Inc. All Rights Reserved. 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 // http://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 merkle 16 17 import ( 18 "bytes" 19 "fmt" 20 21 "github.com/google/trillian/merkle/hashers" 22 "github.com/google/trillian/storage" 23 ) 24 25 // VerifyMapInclusionProof verifies that the passed in expectedRoot can be 26 // reconstructed correctly given the other parameters. 27 // 28 // The process is essentially the same as the inclusion proof checking for 29 // append-only logs, but adds support for nil/"default" proof nodes. 30 // 31 // Returns nil on a successful verification, and an error otherwise. 32 func VerifyMapInclusionProof(treeID int64, index, leaf, expectedRoot []byte, proof [][]byte, h hashers.MapHasher) error { 33 if got, want := len(index)*8, h.BitLen(); got != want { 34 return fmt.Errorf("index len: %d, want %d", got, want) 35 } 36 if got, want := len(proof), h.BitLen(); got != want { 37 return fmt.Errorf("proof len: %d, want %d", got, want) 38 } 39 for i, element := range proof { 40 if got, wanta, wantb := len(element), 0, h.Size(); got != wanta && got != wantb { 41 return fmt.Errorf("proof[%d] len: %d, want %d or %d", i, got, wanta, wantb) 42 } 43 } 44 45 var runningHash []byte 46 if len(leaf) != 0 { 47 leafHash, err := h.HashLeaf(treeID, index, leaf) 48 if err != nil { 49 return fmt.Errorf("HashLeaf(): %v", err) 50 } 51 runningHash = leafHash 52 } 53 54 nID := storage.NewNodeIDFromHash(index) 55 for height, sib := range nID.Siblings() { 56 pElement := proof[height] 57 58 // Since empty values are tied to a location and a level, 59 // HashEmpty(leve1) != HashChildren(E0, E0). 60 // Therefore we need to maintain an empty marker along the 61 // proof path until the first non-empty element so we can call 62 // HashEmpty once at the top of the empty branch. 63 if len(runningHash) == 0 && len(pElement) == 0 { 64 continue 65 } 66 // When we reach a level that has a neighbor, we compute the empty value 67 // for the branch that we are on before combining it with the neighbor. 68 if len(runningHash) == 0 && len(pElement) != 0 { 69 depth := nID.PrefixLenBits - height 70 emptyBranch := nID.Copy().MaskLeft(depth) 71 runningHash = h.HashEmpty(treeID, emptyBranch.Path, height) 72 } 73 74 if len(runningHash) != 0 && len(pElement) == 0 { 75 pElement = h.HashEmpty(treeID, sib.Path, height) 76 } 77 proofIsRightHandElement := nID.Bit(height) == 0 78 if proofIsRightHandElement { 79 runningHash = h.HashChildren(runningHash, pElement) 80 } else { 81 runningHash = h.HashChildren(pElement, runningHash) 82 } 83 } 84 if len(runningHash) == 0 { 85 depth := 0 86 emptyBranch := nID.Copy().MaskLeft(depth) 87 runningHash = h.HashEmpty(treeID, emptyBranch.Path, h.BitLen()) 88 } 89 90 if got, want := runningHash, expectedRoot; !bytes.Equal(got, want) { 91 return fmt.Errorf("calculated root: %x, want \n%x", got, want) 92 } 93 return nil 94 }