-
Notifications
You must be signed in to change notification settings - Fork 0
/
varint.go
100 lines (89 loc) · 2.04 KB
/
varint.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
package massa
import (
"bytes"
"encoding/hex"
"errors"
"math/big"
)
type Varint struct {
buffer bytes.Buffer
}
//NewVarint creates a new variant
func NewVarint() *Varint {
return new(Varint)
}
//GetBytes returns byte data from variant
func (vt *Varint) GetBytes() []byte {
return vt.buffer.Bytes()
}
/*
first byte value
0-249 the same number
250 (0xfa) as uint16
251 (0xfb) as uint32
252 (0xfc) as uint64
253 (0xfd) as uint128
254 (0xfe) as uint256
255 (0xff) as uint512
*/
//generatteVarint generates a variant data
func generatteVarint(number *big.Int, buffer *bytes.Buffer) (*bytes.Buffer, error) {
var buff *bytes.Buffer
if buffer == nil {
buff = &bytes.Buffer{}
} else {
buff = buffer
}
bitLen := number.BitLen()
var b, p int
switch {
case number.Sign() < 0:
return buff, errors.New("error processing negative number")
case number.Sign() == 0:
buff.WriteByte(0)
return buff, nil
case number.Cmp(big.NewInt(249)) <= 0:
buff.WriteByte(number.Bytes()[0])
return buff, nil
case bitLen > 512:
return buff, errors.New("the number is too big")
default:
for b, p = 16, 250; b < 512 && b < bitLen; b, p = b*2, p+1 {
}
//write tag
buff.WriteByte(byte(p))
//write number, BE as LE
numberBytes := number.Bytes()
for i := (bitLen - 1) / 8; i >= 0; i-- {
buff.WriteByte(numberBytes[i])
}
//write leading zeroes (eg 300 bits number & 512 necessary by format)
zeroBytes := (b - bitLen) / 8
for i := 0; i < zeroBytes; i++ {
buff.WriteByte(0)
}
return buff, nil
}
}
//Append adds data to the variant
func (vt *Varint) Append(number *big.Int) error {
_, err := generatteVarint(number, &vt.buffer)
return err
}
//AppendString appends string to the variant
func (vt *Varint) AppendString(str string) error {
bytes, err := hex.DecodeString(str)
if err != nil {
return err
}
vt.AppendBytes(bytes)
return nil
}
//AppendBytes appends bytes to the variant
func (vt *Varint) AppendBytes(bytes []byte) {
if len(bytes) == 0 {
vt.buffer.WriteByte(0)
} else {
vt.buffer.Write(bytes)
}
}