File: hash_bins.go

package info (click to toggle)
golang-github-theupdateframework-go-tuf 2.0.2%2B0.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,908 kB
  • sloc: python: 164; makefile: 89; sh: 37
file content (113 lines) | stat: -rw-r--r-- 3,009 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package targets

import (
	"fmt"
	"strconv"
	"strings"
)

const MinDelegationHashPrefixBitLen = 1
const MaxDelegationHashPrefixBitLen = 32

// hexEncode formats x as a hex string. The hex string is left padded with
// zeros to padWidth, if necessary.
func hexEncode(x uint64, padWidth int) string {
	// Benchmarked to be more than 10x faster than padding with Sprintf.
	s := strconv.FormatUint(x, 16)
	if len(s) >= padWidth {
		return s
	}
	return strings.Repeat("0", padWidth-len(s)) + s
}

const bitsPerHexDigit = 4

// numHexDigits returns the number of hex digits required to encode the given
// number of bits.
func numHexDigits(numBits int) int {
	// ceil(numBits / bitsPerHexDigit)
	return ((numBits - 1) / bitsPerHexDigit) + 1
}

// HashBins represents an ordered list of hash bin target roles, which together
// partition the space of target path hashes equal-sized buckets based on path
// has prefix.
type HashBins struct {
	rolePrefix  string
	bitLen      int
	hexDigitLen int

	numBins           uint64
	numPrefixesPerBin uint64
}

// NewHashBins creates a HashBins partitioning with 2^bitLen buckets.
func NewHashBins(rolePrefix string, bitLen int) (*HashBins, error) {
	if bitLen < MinDelegationHashPrefixBitLen || bitLen > MaxDelegationHashPrefixBitLen {
		return nil, fmt.Errorf("bitLen is out of bounds, should be between %v and %v inclusive", MinDelegationHashPrefixBitLen, MaxDelegationHashPrefixBitLen)
	}

	hexDigitLen := numHexDigits(bitLen)
	numBins := uint64(1) << bitLen

	numPrefixesTotal := uint64(1) << (bitsPerHexDigit * hexDigitLen)
	numPrefixesPerBin := numPrefixesTotal / numBins

	return &HashBins{
		rolePrefix:        rolePrefix,
		bitLen:            bitLen,
		hexDigitLen:       hexDigitLen,
		numBins:           numBins,
		numPrefixesPerBin: numPrefixesPerBin,
	}, nil
}

// NumBins returns the number of hash bin partitions.
func (hb *HashBins) NumBins() uint64 {
	return hb.numBins
}

// GetBin returns the HashBin at index i, or nil if i is out of bounds.
func (hb *HashBins) GetBin(i uint64) *HashBin {
	if i >= hb.numBins {
		return nil
	}

	return &HashBin{
		rolePrefix:  hb.rolePrefix,
		hexDigitLen: hb.hexDigitLen,
		first:       i * hb.numPrefixesPerBin,
		last:        ((i + 1) * hb.numPrefixesPerBin) - 1,
	}
}

// HashBin represents a hex prefix range. First should be less than Last.
type HashBin struct {
	rolePrefix  string
	hexDigitLen int
	first       uint64
	last        uint64
}

// RoleName returns the name of the role that signs for the HashBin.
func (b *HashBin) RoleName() string {
	if b.first == b.last {
		return b.rolePrefix + hexEncode(b.first, b.hexDigitLen)
	}

	return b.rolePrefix + hexEncode(b.first, b.hexDigitLen) + "-" + hexEncode(b.last, b.hexDigitLen)
}

// HashPrefixes returns a slice of all hash prefixes in the bin.
func (b *HashBin) HashPrefixes() []string {
	n := int(b.last - b.first + 1)
	ret := make([]string, int(n))

	x := b.first
	for i := 0; i < n; i++ {
		ret[i] = hexEncode(x, b.hexDigitLen)
		x++
	}

	return ret
}