-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.go
159 lines (124 loc) · 3.12 KB
/
types.go
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package negentropy
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"errors"
"math/big"
)
const IDSize = 32
const FingerprintSize = 16
var modulo = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil)
var ErrBadIDSize = errors.New("bad id size")
type Mode int
const (
SkipMode = iota
FingerprintMode
IdListMode
)
type Item struct {
Timestamp uint64
ID []byte
}
func NewItem(timestamp uint64, id []byte) *Item {
return &Item{Timestamp: timestamp, ID: id}
}
func NewItemWithID(timestamp uint64, id []byte) *Item {
return &Item{Timestamp: timestamp, ID: id}
}
func (i *Item) GetID() []byte {
return i.ID[:]
}
func (i Item) Equals(other Item) bool {
return i.Timestamp == other.Timestamp && bytes.Equal(i.GetID(), other.GetID())
}
func (i Item) LessThan(other Item) bool {
if i.Timestamp != other.Timestamp {
return i.Timestamp < other.Timestamp
}
return bytes.Compare(i.GetID(), other.GetID()) < 0
}
type Bound struct {
Item Item
IDLen int
}
// NewBound creates a new Bound instance with a timestamp and ID.
// It returns an error if the ID size is incorrect.
func NewBound(timestamp uint64, id []byte) (*Bound, error) {
b := &Bound{
Item: *NewItem(timestamp, id),
IDLen: len(id),
}
return b, nil
}
// NewBoundWithItem creates a new Bound instance from an existing Item.
func NewBoundWithItem(item Item) *Bound {
return &Bound{
Item: item,
IDLen: len(item.GetID()),
}
}
// Equals checks if two Bound instances are equal.
func (b Bound) Equals(other Bound) bool {
return b.Item.Equals(other.Item)
}
func (b Bound) LessThan(other Bound) bool {
return b.Item.LessThan(other.Item)
}
type Fingerprint struct {
Buf [FingerprintSize]byte
}
func (f *Fingerprint) SV() []byte {
return f.Buf[:]
}
type Accumulator struct {
Buf []byte
}
func (acc *Accumulator) SetToZero() {
acc.Buf = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}
func (acc *Accumulator) AddItem(other Item) {
acc.AddBytes(other.GetID())
}
func (acc *Accumulator) AddAccumulator(other Accumulator) {
acc.AddBytes(other.Buf)
}
func (acc *Accumulator) AddBytes(other []byte) {
var currCarry, nextCarry uint32
if len(acc.Buf) < 32 {
newBuf := make([]byte, 32)
copy(newBuf, acc.Buf)
acc.Buf = newBuf
}
for i := 0; i < 8; i++ {
offset := i * 4
orig := binary.LittleEndian.Uint32(acc.Buf[offset:])
otherV := binary.LittleEndian.Uint32(other[offset:])
next := orig + currCarry + otherV
if next < orig || next < otherV {
nextCarry = 1
}
binary.LittleEndian.PutUint32(acc.Buf[offset:], next&0xFFFFFFFF)
currCarry = nextCarry
nextCarry = 0
}
}
func (acc *Accumulator) Negate() {
for i := range acc.Buf {
acc.Buf[i] = ^acc.Buf[i]
}
var one []byte
one[0] = 1 // Assuming little-endian; if big-endian, use one[len(one)-1] = 1
acc.AddBytes(one)
}
func (acc *Accumulator) SV() []byte {
return acc.Buf[:]
}
func (acc *Accumulator) GetFingerprint(n int) Fingerprint {
input := acc.SV()
input = append(input, encodeVarInt(n)...)
hash := sha256.Sum256(input)
var fingerprint Fingerprint
copy(fingerprint.Buf[:], hash[:FingerprintSize])
return fingerprint
}