This repository has been archived by the owner on Jul 8, 2023. It is now read-only.
/
base58.go
150 lines (118 loc) · 3.22 KB
/
base58.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
// Copyright 2016 Ivan (Vanya) A. Sergeev (https://github.com/vsergeev)
// Copyright 2017 The coin-network developers
// License: MIT
package curve
import (
"fmt"
"bytes"
"crypto/sha256"
"math/big"
"strings"
)
// b58encode encodes a byte slice b into a base-58 encoded string
func b58encode(b []byte) (s string) {
/* See https://en.bitcoin.it/wiki/Base58Check_encoding */
const BASE58_TABLE = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
/* Convert big endian bytes to big int */
x := new(big.Int).SetBytes(b)
/* Initialize */
r := new(big.Int)
m := big.NewInt(58)
zero := big.NewInt(0)
s = ""
/* Convert big int to string */
for x.Cmp(zero) > 0 {
/* x, r = (x / 58, x % 58) */
x.QuoRem(x, m, r)
/* Prepend ASCII character */
s = string(BASE58_TABLE[r.Int64()]) + s
}
return s
}
// b58decode decodes a base-58 encoded string into a byte slice b.
func b58decode(s string) (b []byte, err error) {
/* See https://en.bitcoin.it/wiki/Base58Check_encoding */
const BASE58_TABLE = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
/* Initialize */
x := big.NewInt(0)
m := big.NewInt(58)
/* Convert string to big int */
for i := 0; i < len(s); i++ {
b58index := strings.IndexByte(BASE58_TABLE, s[i])
if b58index == -1 {
return nil, fmt.Errorf("Invalid base-58 character encountered: '%c', index %d.", s[i], i)
}
b58value := big.NewInt(int64(b58index))
x.Mul(x, m)
x.Add(x, b58value)
}
/* Convert big int to big endian bytes */
b = x.Bytes()
return b, nil
}
// b58checkencode encodes version ver and byte slice b into a base-58 check encoded string.
func b58checkencode(ver uint8, b []byte) (s string) {
/* Prepend version */
bcpy := append([]byte{ver}, b...)
/* Create a new SHA256 context */
sha256_h := sha256.New()
/* SHA256 Hash #1 */
sha256_h.Reset()
sha256_h.Write(bcpy)
hash1 := sha256_h.Sum(nil)
/* SHA256 Hash #2 */
sha256_h.Reset()
sha256_h.Write(hash1)
hash2 := sha256_h.Sum(nil)
/* Append first four bytes of hash */
bcpy = append(bcpy, hash2[0:4]...)
/* Encode base58 string */
s = b58encode(bcpy)
/* For number of leading 0's in bytes, prepend 1 */
for _, v := range bcpy {
if v != 0 {
break
}
s = "1" + s
}
return s
}
// b58checkdecode decodes base-58 check encoded string s into a version ver and byte slice b.
func b58checkdecode(s string) (ver uint8, b []byte, err error) {
/* Decode base58 string */
b, err = b58decode(s)
if err != nil {
return 0, nil, err
}
/* Add leading zero bytes */
for i := 0; i < len(s); i++ {
if s[i] != '1' {
break
}
b = append([]byte{0x00}, b...)
}
/* Verify checksum */
if len(b) < 5 {
return 0, nil, fmt.Errorf("Invalid base-58 check string: missing checksum.")
}
/* Create a new SHA256 context */
sha256_h := sha256.New()
/* SHA256 Hash #1 */
sha256_h.Reset()
sha256_h.Write(b[:len(b)-4])
hash1 := sha256_h.Sum(nil)
/* SHA256 Hash #2 */
sha256_h.Reset()
sha256_h.Write(hash1)
hash2 := sha256_h.Sum(nil)
/* Compare checksum */
if bytes.Compare(hash2[0:4], b[len(b)-4:]) != 0 {
return 0, nil, fmt.Errorf("Invalid base-58 check string: invalid checksum.")
}
/* Strip checksum bytes */
b = b[:len(b)-4]
/* Extract and strip version */
ver = b[0]
b = b[1:]
return ver, b, nil
}