v

Зеркало из https://github.com/vlang/v
Форк
0
/
base58.v 
208 строк · 5.0 Кб
1
// algorthim is adapted from https://github.com/mr-tron/base58 under the MIT license
2

3
module base58
4

5
import math
6

7
// encode_int encodes any integer type to base58 string with Bitcoin alphabet
8
pub fn encode_int(input int) !string {
9
	return encode_int_walpha(input, btc_alphabet)
10
}
11

12
// encode_int_walpha any integer type to base58 string with custom alphabet
13
pub fn encode_int_walpha(input int, alphabet Alphabet) !string {
14
	if input <= 0 {
15
		return error(@MOD + '.' + @FN + ': input must be greater than zero')
16
	}
17

18
	mut buffer := []u8{}
19

20
	mut i := input
21
	for i > 0 {
22
		remainder := i % 58
23
		buffer << alphabet.encode[i8(remainder)]
24
		// This needs to be casted so byte inputs can
25
		// be used. i8 because remainder will never be
26
		// over 58.
27
		i = i / 58
28
	}
29

30
	return buffer.reverse().bytestr()
31
}
32

33
// encode encodes the input string to base58 with the Bitcoin alphabet
34
pub fn encode(input string) string {
35
	return encode_walpha(input, btc_alphabet)
36
}
37

38
// encode_bytes encodes the input array to base58, with the Bitcoin alphabet
39
pub fn encode_bytes(input []u8) []u8 {
40
	return encode_walpha_bytes(input, btc_alphabet)
41
}
42

43
// encode_walpha encodes the input string to base58 with a custom aplhabet
44
pub fn encode_walpha(input string, alphabet Alphabet) string {
45
	if input.len == 0 {
46
		return ''
47
	}
48
	bin := input.bytes()
49
	return encode_walpha_bytes(bin, alphabet).bytestr()
50
}
51

52
// encode_walpha encodes the input array to base58 with a custom aplhabet
53
pub fn encode_walpha_bytes(input []u8, alphabet Alphabet) []u8 {
54
	if input.len == 0 {
55
		return []
56
	}
57
	mut sz := input.len
58

59
	mut zcount := 0
60
	for zcount < sz && input[zcount] == 0 {
61
		zcount++
62
	}
63

64
	// It is crucial to make this as short as possible, especially for
65
	// the usual case of Bitcoin addresses
66
	sz = zcount + (sz - zcount) * 555 / 406 + 1
67
	// integer simplification of
68
	// ceil(log(256)/log(58))
69

70
	mut out := []u8{len: sz}
71
	mut i := 0
72
	mut high := 0
73
	mut carry := u32(0)
74

75
	high = sz - 1
76
	for b in input {
77
		i = sz - 1
78
		for carry = u32(b); i > high || carry != 0; i-- {
79
			carry = carry + 256 * u32(out[i])
80
			out[i] = u8(carry % 58)
81
			carry /= 58
82
		}
83
		high = 1
84
	}
85

86
	// determine additional "zero-gap" in the buffer, aside from zcount
87
	for i = zcount; i < sz && out[i] == 0; i++ {}
88

89
	// now encode the values with actual alphabet in-place
90
	val := unsafe { out[i - zcount..] }
91
	sz = val.len
92
	for i = 0; i < sz; i++ {
93
		out[i] = alphabet.encode[val[i]]
94
	}
95

96
	return out[..sz]
97
}
98

99
// decode_int decodes base58 string to an integer with Bitcoin alphabet
100
pub fn decode_int(input string) !int {
101
	return decode_int_walpha(input, btc_alphabet)
102
}
103

104
// decode_int_walpha decodes base58 string to an integer with custom alphabet
105
pub fn decode_int_walpha(input string, alphabet Alphabet) !int {
106
	mut total := 0 // to hold the results
107
	b58 := input.reverse()
108
	for i, ch in b58 {
109
		ch_i := alphabet.encode.bytestr().index_u8(ch)
110
		if ch_i == -1 {
111
			return error(@MOD + '.' + @FN +
112
				': input string contains values not found in the provided alphabet')
113
		}
114

115
		val := ch_i * math.pow(58, i)
116

117
		total += int(val)
118
	}
119

120
	return total
121
}
122

123
// decode decodes the base58 input string, using the Bitcoin alphabet
124
pub fn decode(str string) !string {
125
	return decode_walpha(str, btc_alphabet)
126
}
127

128
// decode_bytes decodes the base58 encoded input array, using the Bitcoin alphabet
129
pub fn decode_bytes(input []u8) ![]u8 {
130
	return decode_walpha_bytes(input, btc_alphabet)
131
}
132

133
// decode_walpha decodes the base58 encoded input string, using custom alphabet
134
pub fn decode_walpha(input string, alphabet Alphabet) !string {
135
	if input.len == 0 {
136
		return ''
137
	}
138
	bin := input.bytes()
139
	res := decode_walpha_bytes(bin, alphabet)!
140
	return res.bytestr()
141
}
142

143
// decode_walpha_bytes decodes the base58 encoded input array using a custom alphabet
144
pub fn decode_walpha_bytes(input []u8, alphabet Alphabet) ![]u8 {
145
	if input.len == 0 {
146
		return []
147
	}
148

149
	zero := alphabet.encode[0]
150
	b58sz := input.len
151

152
	mut zcount := 0
153
	for i := 0; i < b58sz && input[i] == zero; i++ {
154
		zcount++
155
	}
156

157
	mut t := u64(0)
158
	mut c := u64(0)
159

160
	// the 32-bit algorithm stretches the result up to 2x
161
	mut binu := []u8{len: 2 * ((b58sz * 406 / 555) + 1)}
162
	mut outi := []u32{len: (b58sz + 3) / 4}
163

164
	for _, r in input {
165
		if r > 127 {
166
			panic(@MOD + '.' + @FN +
167
				': high-bit set on invalid digit; outside of ascii range (${r}). This should never happen.')
168
		}
169
		if alphabet.decode[r] == -1 {
170
			return error(@MOD + '.' + @FN + ': invalid base58 digit (${r})')
171
		}
172

173
		c = u64(alphabet.decode[r])
174

175
		for j := outi.len - 1; j >= 0; j-- {
176
			t = u64(outi[j]) * 58 + c
177
			c = t >> 32
178
			outi[j] = u32(t & 0xffffffff)
179
		}
180
	}
181

182
	// initial mask depend on b58sz, on further loops it always starts at 24 bits
183
	mut mask := (u32(b58sz % 4) * 8)
184
	if mask == 0 {
185
		mask = 32
186
	}
187
	mask -= 8
188

189
	mut out_len := 0
190
	for j := 0; j < outi.len; j++ {
191
		for mask < 32 {
192
			binu[out_len] = u8(outi[j] >> mask)
193
			mask -= 8
194
			out_len++
195
		}
196
		mask = 24
197
	}
198

199
	// find the most significant byte post-decode, if any
200
	for msb := zcount; msb < binu.len; msb++ { // loop relies on u32 overflow
201
		if binu[msb] > 0 {
202
			return binu[msb - zcount..out_len]
203
		}
204
	}
205

206
	// it's all zeroes
207
	return binu[..out_len]
208
}
209

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.