in go/cmd/ct-fetch/ct-fetch.go [169:241]
func consistencyProofToSubtrees(proof [][]byte, oldSize, newSize uint64) ([]CtLogSubtree, error) {
// Annotates a consistency proof with the indices needed to check it.
if newSize <= oldSize {
return nil, fmt.Errorf("Empty proof")
}
terms := make([]CtLogSubtree, 0, bits.Len64(newSize)+2)
// A consistency proof between |oldSize| and |newSize| is
// "almost" an inclusion proof for index |oldSize|-1 in the tree
// of size |newSize|. "Almost" because we can omit terms from
// the old tree so long as we provide enough information to
// recover the old tree head.
//
// We represent the current node by the the set of leaves below
// it, so each internal node of the tree looks like:
// [low, high]
// / \
// [low, mid-1] [mid, high]
// (The value of mid is determined by the size of the [low, high]
// interval.)
//
// We will traverse from the root towards the leaf at index
// |oldSize|-1, and we will record the set of leaves that lie
// below the sibling of each node that we visit.
//
cursor := CtLogSubtree{First: uint64(0), Last: uint64(newSize - 1)}
target := uint64(oldSize - 1)
// We walk down the tree until we reach a leaf (low == high) or
// a node which is in the old tree (high <= target). Both conditions
// are necessary if we are to handle the |oldSize| = 0 case.
//
for cursor.First != cursor.Last && cursor.Last != target {
mid := cursor.Midpoint()
if target < mid {
terms = append(terms, CtLogSubtree{First: mid, Last: cursor.Last})
cursor.Last = mid - 1
} else {
terms = append(terms, CtLogSubtree{First: cursor.First, Last: mid - 1})
cursor.First = mid
}
}
// The cursor is at node [low, high] and we have just recorded
// this node's sibling. We need to record enough information to
// recover the old tree head. If |oldSize| is a power of two,
// then the current node is the old tree head and the caller
// already knows its value. Otherwise we need to record the
// current node so that the caller can recover the old tree
// head.
//
if (oldSize & (oldSize - 1)) != 0 { // 0 < |oldSize| is not a power of 2
terms = append(terms, cursor)
}
if len(terms) != len(proof) {
return nil, fmt.Errorf("Expected proof of length %d and got %d.",
len(terms), len(proof))
}
// Reverse the list to conform with the presentation from RFC 6962
for i, j := 0, len(terms)-1; i < j; i, j = i+1, j-1 {
terms[i], terms[j] = terms[j], terms[i]
}
for i := 0; i < len(proof); i++ {
terms[i].Root = proof[i]
}
return terms, nil
}