func verifyProof(s *Snapshot, index, value []byte, proof *proto.TreeProof) { reconstructed, err := coname.ReconstructTree(proof, coname.ToBits(coname.IndexBits, index)) if err != nil { panic(err) } redoneLookup, err := coname.TreeLookup(reconstructed, index) if err != nil { panic(err) } if got, want := redoneLookup, value; !bytes.Equal(got, want) { log.Panicf("reconstructed lookup got different result: %v rather than %v", got, want) } recomputedHash, err := coname.RecomputeHash(treeNonce, reconstructed) if err != nil { panic(err) } rootHash, err := s.GetRootHash() if err != nil { panic(err) } if got, want := recomputedHash, rootHash; !bytes.Equal(got, want) { log.Panicf("reconstructed hash differed: %x rather than %x", got, want) } }
// Set updates the leaf value at the index (or inserts it if it did not exist). // In-memory: doesn't actually touch the disk yet. func (snapshot *NewSnapshot) Set(indexBytes []byte, value []byte) (err error) { if len(indexBytes) != coname.IndexBytes { return fmt.Errorf("Wrong index length") } if len(value) != coname.HashBytes { return fmt.Errorf("Wrong value length") } value = append([]byte(nil), value...) // Make a copy of value indexBits := coname.ToBits(coname.IndexBits, indexBytes) nodePointer := &snapshot.root position := 0 // Traverse down the tree, following either the left or right child depending on the next bit. for *nodePointer != nil && !(*nodePointer).isLeaf { nodePointer, err = snapshot.tree.getChildPointer(*nodePointer, indexBits[position]) if err != nil { return } position++ } if *nodePointer == nil { // We've hit an empty branch where this leaf belongs -- put it there. *nodePointer = &node{ diskNode: diskNode{ isLeaf: true, indexBytes: append([]byte{}, indexBytes...), // Make a copy of indexBytes value: value, }, prefixBits: indexBits[:position], } } else if bytes.Equal((*nodePointer).indexBytes, indexBytes) { // We have an existing leaf at this index; just replace the value (*nodePointer).value = value } else { // We have a different leaf with a matching prefix. We'll have to create new intermediate nodes. oldLeaf := *nodePointer oldLeafIndexBits := coname.ToBits(coname.IndexBits, oldLeaf.indexBytes) // Create a new intermediate node for each bit that has now become shared. for oldLeafIndexBits[position] == indexBits[position] { newNode := &node{ diskNode: diskNode{ isLeaf: false, }, prefixBits: indexBits[:position], } *nodePointer, nodePointer = newNode, &newNode.children[coname.BitToIndex(indexBits[position])] position++ } // Create a new node at which the tree now branches. splitNode := &node{ diskNode: diskNode{ isLeaf: false, }, prefixBits: indexBits[:position], } // Create the new leaf under the splitNode newLeaf := &node{ diskNode: diskNode{ isLeaf: true, indexBytes: append([]byte{}, indexBytes...), // Make a copy of the index value: value, }, prefixBits: indexBits[:position+1], } // Move the old leaf's index down oldLeaf.prefixBits = oldLeafIndexBits[:position+1] splitNode.children[coname.BitToIndex(indexBits[position])] = newLeaf splitNode.children[coname.BitToIndex(oldLeafIndexBits[position])] = oldLeaf *nodePointer = splitNode } return nil }