type Hash … const HashSize … // String returns a base64 representation of the hash for printing. func (h Hash) String() string { … } // MarshalJSON marshals the hash as a JSON string containing the base64-encoded hash. func (h Hash) MarshalJSON() ([]byte, error) { … } // UnmarshalJSON unmarshals a hash from JSON string containing the a base64-encoded hash. func (h *Hash) UnmarshalJSON(data []byte) error { … } // ParseHash parses the base64-encoded string form of a hash. func ParseHash(s string) (Hash, error) { … } // maxpow2 returns k, the maximum power of 2 smaller than n, // as well as l = log₂ k (so k = 1<<l). func maxpow2(n int64) (k int64, l int) { … } var zeroPrefix … // RecordHash returns the content hash for the given record data. func RecordHash(data []byte) Hash { … } // NodeHash returns the hash for an interior tree node with the given left and right hashes. func NodeHash(left, right Hash) Hash { … } // StoredHashIndex maps the tree coordinates (level, n) // to a dense linear ordering that can be used for hash storage. // Hash storage implementations that store hashes in sequential // storage can use this function to compute where to read or write // a given hash. func StoredHashIndex(level int, n int64) int64 { … } // SplitStoredHashIndex is the inverse of [StoredHashIndex]. // That is, SplitStoredHashIndex(StoredHashIndex(level, n)) == level, n. func SplitStoredHashIndex(index int64) (level int, n int64) { … } // StoredHashCount returns the number of stored hashes // that are expected for a tree with n records. func StoredHashCount(n int64) int64 { … } // StoredHashes returns the hashes that must be stored when writing // record n with the given data. The hashes should be stored starting // at StoredHashIndex(0, n). The result will have at most 1 + log₂ n hashes, // but it will average just under two per call for a sequence of calls for n=1..k. // // StoredHashes may read up to log n earlier hashes from r // in order to compute hashes for completed subtrees. func StoredHashes(n int64, data []byte, r HashReader) ([]Hash, error) { … } // StoredHashesForRecordHash is like [StoredHashes] but takes // as its second argument RecordHash(data) instead of data itself. func StoredHashesForRecordHash(n int64, h Hash, r HashReader) ([]Hash, error) { … } type HashReader … type HashReaderFunc … func (f HashReaderFunc) ReadHashes(indexes []int64) ([]Hash, error) { … } var emptyHash … // TreeHash computes the hash for the root of the tree with n records, // using the HashReader to obtain previously stored hashes // (those returned by StoredHashes during the writes of those n records). // TreeHash makes a single call to ReadHash requesting at most 1 + log₂ n hashes. func TreeHash(n int64, r HashReader) (Hash, error) { … } // subTreeIndex returns the storage indexes needed to compute // the hash for the subtree containing records [lo, hi), // appending them to need and returning the result. // See https://tools.ietf.org/html/rfc6962#section-2.1 func subTreeIndex(lo, hi int64, need []int64) []int64 { … } // subTreeHash computes the hash for the subtree containing records [lo, hi), // assuming that hashes are the hashes corresponding to the indexes // returned by subTreeIndex(lo, hi). // It returns any leftover hashes. func subTreeHash(lo, hi int64, hashes []Hash) (Hash, []Hash) { … } type RecordProof … // ProveRecord returns the proof that the tree of size t contains the record with index n. func ProveRecord(t, n int64, r HashReader) (RecordProof, error) { … } // leafProofIndex builds the list of indexes needed to construct the proof // that leaf n is contained in the subtree with leaves [lo, hi). // It appends those indexes to need and returns the result. // See https://tools.ietf.org/html/rfc6962#section-2.1.1 func leafProofIndex(lo, hi, n int64, need []int64) []int64 { … } // leafProof constructs the proof that leaf n is contained in the subtree with leaves [lo, hi). // It returns any leftover hashes as well. // See https://tools.ietf.org/html/rfc6962#section-2.1.1 func leafProof(lo, hi, n int64, hashes []Hash) (RecordProof, []Hash) { … } var errProofFailed … // CheckRecord verifies that p is a valid proof that the tree of size t // with hash th has an n'th record with hash h. func CheckRecord(p RecordProof, t int64, th Hash, n int64, h Hash) error { … } // runRecordProof runs the proof p that leaf n is contained in the subtree with leaves [lo, hi). // Running the proof means constructing and returning the implied hash of that // subtree. func runRecordProof(p RecordProof, lo, hi, n int64, leafHash Hash) (Hash, error) { … } type TreeProof … // ProveTree returns the proof that the tree of size t contains // as a prefix all the records from the tree of smaller size n. func ProveTree(t, n int64, h HashReader) (TreeProof, error) { … } // treeProofIndex builds the list of indexes needed to construct // the sub-proof related to the subtree containing records [lo, hi). // See https://tools.ietf.org/html/rfc6962#section-2.1.2. func treeProofIndex(lo, hi, n int64, need []int64) []int64 { … } // treeProof constructs the sub-proof related to the subtree containing records [lo, hi). // It returns any leftover hashes as well. // See https://tools.ietf.org/html/rfc6962#section-2.1.2. func treeProof(lo, hi, n int64, hashes []Hash) (TreeProof, []Hash) { … } // CheckTree verifies that p is a valid proof that the tree of size t with hash th // contains as a prefix the tree of size n with hash h. func CheckTree(p TreeProof, t int64, th Hash, n int64, h Hash) error { … } // runTreeProof runs the sub-proof p related to the subtree containing records [lo, hi), // where old is the hash of the old tree with n records. // Running the proof means constructing and returning the implied hashes of that // subtree in both the old and new tree. func runTreeProof(p TreeProof, lo, hi, n int64, old Hash) (Hash, Hash, error) { … }