-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnano.go
88 lines (77 loc) · 1.82 KB
/
nano.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
package main
import (
"errors"
"golang.org/x/crypto/blake2b"
)
var (
ErrInvalidPublicKey = errors.New("nano: invalid public key")
)
var base32Alphabet = [32]byte{
'1', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'w', 'x', 'y', 'z'}
// Define some binary "literals" for the massive bit manipulation operation
// when converting public key to account string.
const (
b11111 = 31
b01111 = 15
b00111 = 7
b00011 = 3
b00001 = 1
)
type encodeAddressBuf struct {
check []byte
publicKey []byte
}
func (b *encodeAddressBuf) GetByte(i int) byte {
if i < len(b.check) {
return b.check[i]
} else if i-len(b.check) < len(b.publicKey) {
return b.publicKey[len(b.publicKey)-1-(i-len(b.check))]
}
return 0
}
func EncodeAddress(publicKey []byte) (string, error) {
if len(publicKey) != 32 {
return "", ErrInvalidPublicKey
}
h, err := blake2b.New(5, nil)
if err != nil {
return "", err
}
h.Write(publicKey)
check := h.Sum(nil)
raw := make([]byte, 60)
buf := encodeAddressBuf{
check: check,
publicKey: publicKey,
}
for k := 0; k < len(raw); k++ {
i := (k / 8) * 5
var c byte
switch k % 8 {
case 0:
c = buf.GetByte(i) & b11111
case 1:
c = (buf.GetByte(i) >> 5) & b00111
c |= (buf.GetByte(i+1) & b00011) << 3
case 2:
c = (buf.GetByte(i+1) >> 2) & b11111
case 3:
c = (buf.GetByte(i+1) >> 7) & b00001
c |= (buf.GetByte(i+2) & b01111) << 1
case 4:
c = (buf.GetByte(i+2) >> 4) & b01111
c |= (buf.GetByte(i+3) & b00001) << 4
case 5:
c = (buf.GetByte(i+3) >> 1) & b11111
case 6:
c = (buf.GetByte(i+3) >> 6) & b00011
c |= (buf.GetByte(i+4) & b00111) << 2
case 7:
c = (buf.GetByte(i+4) >> 3) & b11111
}
raw[len(raw)-1-k] = base32Alphabet[c]
}
return "nano_" + string(raw), nil
}