summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/go/internal/tlog/tile.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/go/internal/tlog/tile.go')
-rw-r--r--libgo/go/cmd/go/internal/tlog/tile.go418
1 files changed, 0 insertions, 418 deletions
diff --git a/libgo/go/cmd/go/internal/tlog/tile.go b/libgo/go/cmd/go/internal/tlog/tile.go
deleted file mode 100644
index 694d89cdf26..00000000000
--- a/libgo/go/cmd/go/internal/tlog/tile.go
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tlog
-
-import (
- "fmt"
- "strconv"
- "strings"
-)
-
-// A Tile is a description of a transparency log tile.
-// A tile of height H at level L offset N lists W consecutive hashes
-// at level H*L of the tree starting at offset N*(2**H).
-// A complete tile lists 2**H hashes; a partial tile lists fewer.
-// Note that a tile represents the entire subtree of height H
-// with those hashes as the leaves. The levels above H*L
-// can be reconstructed by hashing the leaves.
-//
-// Each Tile can be encoded as a “tile coordinate path”
-// of the form tile/H/L/NNN[.p/W].
-// The .p/W suffix is present only for partial tiles, meaning W < 2**H.
-// The NNN element is an encoding of N into 3-digit path elements.
-// All but the last path element begins with an "x".
-// For example,
-// Tile{H: 3, L: 4, N: 1234067, W: 1}'s path
-// is tile/3/4/x001/x234/067.p/1, and
-// Tile{H: 3, L: 4, N: 1234067, W: 8}'s path
-// is tile/3/4/x001/x234/067.
-// See Tile's Path method and the ParseTilePath function.
-//
-// The special level L=-1 holds raw record data instead of hashes.
-// In this case, the level encodes into a tile path as the path element
-// "data" instead of "-1".
-type Tile struct {
- H int // height of tile (1 ≤ H ≤ 30)
- L int // level in tiling (-1 ≤ L ≤ 63)
- N int64 // number within level (0 ≤ N, unbounded)
- W int // width of tile (1 ≤ W ≤ 2**H; 2**H is complete tile)
-}
-
-// TileForIndex returns the tile of height h ≥ 1
-// and least width storing the given hash storage index.
-func TileForIndex(h int, index int64) Tile {
- if h < 1 {
- panic("TileForIndex: invalid height")
- }
- t, _, _ := tileForIndex(h, index)
- return t
-}
-
-// tileForIndex returns the tile of height h ≥ 1
-// storing the given hash index, which can be
-// reconstructed using tileHash(data[start:end]).
-func tileForIndex(h int, index int64) (t Tile, start, end int) {
- level, n := SplitStoredHashIndex(index)
- t.H = h
- t.L = level / h
- level -= t.L * h // now level within tile
- t.N = n << uint(level) >> uint(t.H)
- n -= t.N << uint(t.H) >> uint(level) // now n within tile at level
- t.W = int((n + 1) << uint(level))
- return t, int(n<<uint(level)) * HashSize, int((n+1)<<uint(level)) * HashSize
-}
-
-// HashFromTile returns the hash at the given storage index,
-// provided that t == TileForIndex(t.H, index) or a wider version,
-// and data is t's tile data (of length at least t.W*HashSize).
-func HashFromTile(t Tile, data []byte, index int64) (Hash, error) {
- if t.H < 1 || t.H > 30 || t.L < 0 || t.L >= 64 || t.W < 1 || t.W > 1<<uint(t.H) {
- return Hash{}, fmt.Errorf("invalid tile %v", t.Path())
- }
- if len(data) < t.W*HashSize {
- return Hash{}, fmt.Errorf("data len %d too short for tile %v", len(data), t.Path())
- }
- t1, start, end := tileForIndex(t.H, index)
- if t.L != t1.L || t.N != t1.N || t.W < t1.W {
- return Hash{}, fmt.Errorf("index %v is in %v not %v", index, t1.Path(), t.Path())
- }
- return tileHash(data[start:end]), nil
-}
-
-// tileHash computes the subtree hash corresponding to the (2^K)-1 hashes in data.
-func tileHash(data []byte) Hash {
- if len(data) == 0 {
- panic("bad math in tileHash")
- }
- if len(data) == HashSize {
- var h Hash
- copy(h[:], data)
- return h
- }
- n := len(data) / 2
- return NodeHash(tileHash(data[:n]), tileHash(data[n:]))
-}
-
-// NewTiles returns the coordinates of the tiles of height h ≥ 1
-// that must be published when publishing from a tree of
-// size newTreeSize to replace a tree of size oldTreeSize.
-// (No tiles need to be published for a tree of size zero.)
-func NewTiles(h int, oldTreeSize, newTreeSize int64) []Tile {
- if h < 1 {
- panic(fmt.Sprintf("NewTiles: invalid height %d", h))
- }
- H := uint(h)
- var tiles []Tile
- for level := uint(0); newTreeSize>>(H*level) > 0; level++ {
- oldN := oldTreeSize >> (H * level)
- newN := newTreeSize >> (H * level)
- for n := oldN >> H; n < newN>>H; n++ {
- tiles = append(tiles, Tile{H: h, L: int(level), N: n, W: 1 << H})
- }
- n := newN >> H
- maxW := int(newN - n<<H)
- minW := 1
- if oldN > n<<H {
- minW = int(oldN - n<<H)
- }
- for w := minW; w <= maxW; w++ {
- tiles = append(tiles, Tile{H: h, L: int(level), N: n, W: w})
- }
- }
- return tiles
-}
-
-// ReadTileData reads the hashes for tile t from r
-// and returns the corresponding tile data.
-func ReadTileData(t Tile, r HashReader) ([]byte, error) {
- size := t.W
- if size == 0 {
- size = 1 << uint(t.H)
- }
- start := t.N << uint(t.H)
- indexes := make([]int64, size)
- for i := 0; i < size; i++ {
- indexes[i] = StoredHashIndex(t.H*t.L, start+int64(i))
- }
-
- hashes, err := r.ReadHashes(indexes)
- if err != nil {
- return nil, err
- }
- if len(hashes) != len(indexes) {
- return nil, fmt.Errorf("tlog: ReadHashes(%d indexes) = %d hashes", len(indexes), len(hashes))
- }
-
- tile := make([]byte, size*HashSize)
- for i := 0; i < size; i++ {
- copy(tile[i*HashSize:], hashes[i][:])
- }
- return tile, nil
-}
-
-// To limit the size of any particular directory listing,
-// we encode the (possibly very large) number N
-// by encoding three digits at a time.
-// For example, 123456789 encodes as x123/x456/789.
-// Each directory has at most 1000 each xNNN, NNN, and NNN.p children,
-// so there are at most 3000 entries in any one directory.
-const pathBase = 1000
-
-// Path returns a tile coordinate path describing t.
-func (t Tile) Path() string {
- n := t.N
- nStr := fmt.Sprintf("%03d", n%pathBase)
- for n >= pathBase {
- n /= pathBase
- nStr = fmt.Sprintf("x%03d/%s", n%pathBase, nStr)
- }
- pStr := ""
- if t.W != 1<<uint(t.H) {
- pStr = fmt.Sprintf(".p/%d", t.W)
- }
- var L string
- if t.L == -1 {
- L = "data"
- } else {
- L = fmt.Sprintf("%d", t.L)
- }
- return fmt.Sprintf("tile/%d/%s/%s%s", t.H, L, nStr, pStr)
-}
-
-// ParseTilePath parses a tile coordinate path.
-func ParseTilePath(path string) (Tile, error) {
- f := strings.Split(path, "/")
- if len(f) < 4 || f[0] != "tile" {
- return Tile{}, &badPathError{path}
- }
- h, err1 := strconv.Atoi(f[1])
- isData := false
- if f[2] == "data" {
- isData = true
- f[2] = "0"
- }
- l, err2 := strconv.Atoi(f[2])
- if err1 != nil || err2 != nil || h < 1 || l < 0 || h > 30 {
- return Tile{}, &badPathError{path}
- }
- w := 1 << uint(h)
- if dotP := f[len(f)-2]; strings.HasSuffix(dotP, ".p") {
- ww, err := strconv.Atoi(f[len(f)-1])
- if err != nil || ww <= 0 || ww >= w {
- return Tile{}, &badPathError{path}
- }
- w = ww
- f[len(f)-2] = dotP[:len(dotP)-len(".p")]
- f = f[:len(f)-1]
- }
- f = f[3:]
- n := int64(0)
- for _, s := range f {
- nn, err := strconv.Atoi(strings.TrimPrefix(s, "x"))
- if err != nil || nn < 0 || nn >= pathBase {
- return Tile{}, &badPathError{path}
- }
- n = n*pathBase + int64(nn)
- }
- if isData {
- l = -1
- }
- t := Tile{H: h, L: l, N: n, W: w}
- if path != t.Path() {
- return Tile{}, &badPathError{path}
- }
- return t, nil
-}
-
-type badPathError struct {
- path string
-}
-
-func (e *badPathError) Error() string {
- return fmt.Sprintf("malformed tile path %q", e.path)
-}
-
-// A TileReader reads tiles from a go.sum database log.
-type TileReader interface {
- // Height returns the height of the available tiles.
- Height() int
-
- // ReadTiles returns the data for each requested tile.
- // If ReadTiles returns err == nil, it must also return
- // a data record for each tile (len(data) == len(tiles))
- // and each data record must be the correct length
- // (len(data[i]) == tiles[i].W*HashSize).
- ReadTiles(tiles []Tile) (data [][]byte, err error)
-
- // SaveTiles informs the TileReader that the tile data
- // returned by ReadTiles has been confirmed as valid
- // and can be saved in persistent storage (on disk).
- SaveTiles(tiles []Tile, data [][]byte)
-}
-
-// TileHashReader returns a HashReader that satisfies requests
-// by loading tiles of the given tree.
-//
-// The returned HashReader checks that loaded tiles are
-// valid for the given tree. Therefore, any hashes returned
-// by the HashReader are already proven to be in the tree.
-func TileHashReader(tree Tree, tr TileReader) HashReader {
- return &tileHashReader{tree: tree, tr: tr}
-}
-
-type tileHashReader struct {
- tree Tree
- tr TileReader
-}
-
-// tileParent returns t's k'th tile parent in the tiles for a tree of size n.
-// If there is no such parent, tileParent returns Tile{}.
-func tileParent(t Tile, k int, n int64) Tile {
- t.L += k
- t.N >>= uint(k * t.H)
- t.W = 1 << uint(t.H)
- if max := n >> uint(t.L*t.H); t.N<<uint(t.H)+int64(t.W) >= max {
- if t.N<<uint(t.H) >= max {
- return Tile{}
- }
- t.W = int(max - t.N<<uint(t.H))
- }
- return t
-}
-
-func (r *tileHashReader) ReadHashes(indexes []int64) ([]Hash, error) {
- h := r.tr.Height()
-
- tileOrder := make(map[Tile]int) // tileOrder[tileKey(tiles[i])] = i
- var tiles []Tile
-
- // Plan to fetch tiles necessary to recompute tree hash.
- // If it matches, those tiles are authenticated.
- stx := subTreeIndex(0, r.tree.N, nil)
- stxTileOrder := make([]int, len(stx))
- for i, x := range stx {
- tile, _, _ := tileForIndex(h, x)
- tile = tileParent(tile, 0, r.tree.N)
- if j, ok := tileOrder[tile]; ok {
- stxTileOrder[i] = j
- continue
- }
- stxTileOrder[i] = len(tiles)
- tileOrder[tile] = len(tiles)
- tiles = append(tiles, tile)
- }
-
- // Plan to fetch tiles containing the indexes,
- // along with any parent tiles needed
- // for authentication. For most calls,
- // the parents are being fetched anyway.
- indexTileOrder := make([]int, len(indexes))
- for i, x := range indexes {
- if x >= StoredHashIndex(0, r.tree.N) {
- return nil, fmt.Errorf("indexes not in tree")
- }
-
- tile, _, _ := tileForIndex(h, x)
-
- // Walk up parent tiles until we find one we've requested.
- // That one will be authenticated.
- k := 0
- for ; ; k++ {
- p := tileParent(tile, k, r.tree.N)
- if j, ok := tileOrder[p]; ok {
- if k == 0 {
- indexTileOrder[i] = j
- }
- break
- }
- }
-
- // Walk back down recording child tiles after parents.
- // This loop ends by revisiting the tile for this index
- // (tileParent(tile, 0, r.tree.N)) unless k == 0, in which
- // case the previous loop did it.
- for k--; k >= 0; k-- {
- p := tileParent(tile, k, r.tree.N)
- if p.W != 1<<uint(p.H) {
- // Only full tiles have parents.
- // This tile has a parent, so it must be full.
- return nil, fmt.Errorf("bad math in tileHashReader: %d %d %v", r.tree.N, x, p)
- }
- tileOrder[p] = len(tiles)
- if k == 0 {
- indexTileOrder[i] = len(tiles)
- }
- tiles = append(tiles, p)
- }
- }
-
- // Fetch all the tile data.
- data, err := r.tr.ReadTiles(tiles)
- if err != nil {
- return nil, err
- }
- if len(data) != len(tiles) {
- return nil, fmt.Errorf("TileReader returned bad result slice (len=%d, want %d)", len(data), len(tiles))
- }
- for i, tile := range tiles {
- if len(data[i]) != tile.W*HashSize {
- return nil, fmt.Errorf("TileReader returned bad result slice (%v len=%d, want %d)", tile.Path(), len(data[i]), tile.W*HashSize)
- }
- }
-
- // Authenticate the initial tiles against the tree hash.
- // They are arranged so that parents are authenticated before children.
- // First the tiles needed for the tree hash.
- th, err := HashFromTile(tiles[stxTileOrder[len(stx)-1]], data[stxTileOrder[len(stx)-1]], stx[len(stx)-1])
- if err != nil {
- return nil, err
- }
- for i := len(stx) - 2; i >= 0; i-- {
- h, err := HashFromTile(tiles[stxTileOrder[i]], data[stxTileOrder[i]], stx[i])
- if err != nil {
- return nil, err
- }
- th = NodeHash(h, th)
- }
- if th != r.tree.Hash {
- // The tiles do not support the tree hash.
- // We know at least one is wrong, but not which one.
- return nil, fmt.Errorf("downloaded inconsistent tile")
- }
-
- // Authenticate full tiles against their parents.
- for i := len(stx); i < len(tiles); i++ {
- tile := tiles[i]
- p := tileParent(tile, 1, r.tree.N)
- j, ok := tileOrder[p]
- if !ok {
- return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost parent of %v", r.tree.N, indexes, tile)
- }
- h, err := HashFromTile(p, data[j], StoredHashIndex(p.L*p.H, tile.N))
- if err != nil {
- return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost hash of %v: %v", r.tree.N, indexes, tile, err)
- }
- if h != tileHash(data[i]) {
- return nil, fmt.Errorf("downloaded inconsistent tile")
- }
- }
-
- // Now we have all the tiles needed for the requested hashes,
- // and we've authenticated the full tile set against the trusted tree hash.
- r.tr.SaveTiles(tiles, data)
-
- // Pull out the requested hashes.
- hashes := make([]Hash, len(indexes))
- for i, x := range indexes {
- j := indexTileOrder[i]
- h, err := HashFromTile(tiles[j], data[j], x)
- if err != nil {
- return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost hash %v: %v", r.tree.N, indexes, x, err)
- }
- hashes[i] = h
- }
-
- return hashes, nil
-}