-
Notifications
You must be signed in to change notification settings - Fork 5
/
forge.go
124 lines (105 loc) · 2.21 KB
/
forge.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
package forge
import (
"bytes"
"fmt"
"math"
"strconv"
"github.com/dipdup-net/go-lib/tools/types"
"github.com/ebellocchia/go-base58"
"github.com/pkg/errors"
)
// ForgeNat -
func ForgeNat(value *types.BigInt) ([]byte, error) {
if value == nil || value.Sign() == -1 {
return nil, errors.Errorf("invalid nat value: %v", value)
}
buf := new(bytes.Buffer)
val := value.Int64()
var end bool
for !end {
b := byte(val & 0x7f)
val >>= 7
end = val <= 0
if !end {
b |= 0x80
}
buf.WriteByte(b)
}
return buf.Bytes(), nil
}
// ForgeInt -
func ForgeInt(value *types.BigInt) ([]byte, error) {
if value == nil {
return nil, errors.New("Invalid int value")
}
isNegative := value.Sign() == -1
bits := value.Text(2)
if isNegative {
bits = bits[1:]
}
bitsCount := len(bits)
var pad int
switch {
case (bitsCount-6)%7 == 0:
pad = bitsCount
case bitsCount > 6:
pad = bitsCount + 7 - (bitsCount-6)%7
default:
pad = 6
}
bits = fmt.Sprintf("%0*s", pad, bits)
segments := make([]string, 0)
for i := 0; i <= pad/7; i++ {
idx := 7 * i
length := int(math.Min(7, float64(pad-7*i)))
segments = append(segments, bits[idx:(idx+length)])
}
segments = reverse(segments)
if isNegative {
segments[0] = fmt.Sprintf("1%s", segments[0])
} else {
segments[0] = fmt.Sprintf("0%s", segments[0])
}
data := make([]byte, 0)
for i := 0; i < len(segments); i++ {
prefix := "1"
if i == len(segments)-1 {
prefix = "0"
}
val, err := strconv.ParseUint(prefix+segments[i], 2, 8)
if err != nil {
return nil, err
}
data = append(data, byte(val))
}
return data, nil
}
// ForgeBool -
func ForgeBool(value bool) []byte {
if value {
return []byte{255}
}
return []byte{0}
}
// ForgeString -
func ForgeString(value string) ([]byte, error) {
decoded, err := base58.New(base58.AlphabetBitcoin).Decode(value)
if err != nil {
return nil, err
}
return decoded[2 : len(decoded)-4], nil
}
func reverse(arr []string) []string {
for i := len(arr)/2 - 1; i >= 0; i-- {
opp := len(arr) - 1 - i
arr[i], arr[opp] = arr[opp], arr[i]
}
return arr
}
func reverseBytes(arr []byte) []byte {
for i := len(arr)/2 - 1; i >= 0; i-- {
opp := len(arr) - 1 - i
arr[i], arr[opp] = arr[opp], arr[i]
}
return arr
}