1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

encoding.base58: remove one unnecessary map access per the most common BTC usages; implement encode_bytes, decode_bytes, encode_walpha_bytes, decode_walpha_bytes functions

This commit is contained in:
Delyan Angelov 2022-08-08 15:33:16 +03:00
parent 6a728e1674
commit 5a834a2ef9
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
3 changed files with 107 additions and 37 deletions

View File

@ -1,23 +1,24 @@
module base58
// alphabets is a map of common base58 alphabets
pub const alphabets = init_alphabets()
const impossible = 'this should never happen'
// init_alphabet instantiates the preconfigured `Alphabet`s and returns them as `map[string]Alphabet`.
// This is a temporary function. Setting const alphabets to the value returned in this function
// causes a C error right now.
fn init_alphabets() map[string]Alphabet {
return {
'btc': new_alphabet('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz') or {
panic(@MOD + '.' + @FN + ': this should never happen')
pub const btc_alphabet = new_alphabet('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz') or {
panic(impossible)
}
'flickr': new_alphabet('123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ') or {
panic(@MOD + '.' + @FN + ': this should never happen')
}
'ripple': new_alphabet('rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz') or {
panic(@MOD + '.' + @FN + ': this should never happen')
pub const flickr_alphabet = new_alphabet('123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ') or {
panic(impossible)
}
pub const ripple_alphabet = new_alphabet('rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz') or {
panic(impossible)
}
// alphabets is a map of common base58 alphabets:
pub const alphabets = {
'btc': btc_alphabet
'flickr': flickr_alphabet
'ripple': ripple_alphabet
}
// Alphabet is the series of characters that an input

View File

@ -6,7 +6,7 @@ import math
// encode_int encodes any integer type to base58 string with Bitcoin alphabet
pub fn encode_int(input int) ?string {
return encode_int_walpha(input, alphabets['btc'])
return encode_int_walpha(input, btc_alphabet)
}
// encode_int_walpha any integer type to base58 string with custom alphabet
@ -30,22 +30,34 @@ pub fn encode_int_walpha(input int, alphabet Alphabet) ?string {
return buffer.reverse().bytestr()
}
// encode encodes byte array to base58 with Bitcoin alphabet
// encode encodes the input string to base58 with the Bitcoin alphabet
pub fn encode(input string) string {
return encode_walpha(input, alphabets['btc'])
return encode_walpha(input, btc_alphabet)
}
// encode_walpha encodes byte array to base58 with custom aplhabet
// encode_bytes encodes the input array to base58, with the Bitcoin alphabet
pub fn encode_bytes(input []u8) []u8 {
return encode_walpha_bytes(input, btc_alphabet)
}
// encode_walpha encodes the input string to base58 with a custom aplhabet
pub fn encode_walpha(input string, alphabet Alphabet) string {
if input.len == 0 {
return ''
}
bin := input.bytes()
mut sz := bin.len
return encode_walpha_bytes(bin, alphabet).bytestr()
}
// encode_walpha encodes the input array to base58 with a custom aplhabet
pub fn encode_walpha_bytes(input []u8, alphabet Alphabet) []u8 {
if input.len == 0 {
return []
}
mut sz := input.len
mut zcount := 0
for zcount < sz && bin[zcount] == 0 {
for zcount < sz && input[zcount] == 0 {
zcount++
}
@ -61,7 +73,7 @@ pub fn encode_walpha(input string, alphabet Alphabet) string {
mut carry := u32(0)
high = sz - 1
for b in bin {
for b in input {
i = sz - 1
for carry = u32(b); i > high || carry != 0; i-- {
carry = carry + 256 * u32(out[i])
@ -81,12 +93,12 @@ pub fn encode_walpha(input string, alphabet Alphabet) string {
out[i] = alphabet.encode[val[i]]
}
return out[..sz].bytestr()
return out[..sz]
}
// decode_int decodes base58 string to an integer with Bitcoin alphabet
pub fn decode_int(input string) ?int {
return decode_int_walpha(input, alphabets['btc'])
return decode_int_walpha(input, btc_alphabet)
}
// decode_int_walpha decodes base58 string to an integer with custom alphabet
@ -108,22 +120,37 @@ pub fn decode_int_walpha(input string, alphabet Alphabet) ?int {
return total
}
// decode decodes base58 string using the Bitcoin alphabet
// decode decodes the base58 input string, using the Bitcoin alphabet
pub fn decode(str string) ?string {
return decode_walpha(str, alphabets['btc'])
return decode_walpha(str, btc_alphabet)
}
// decode_walpha decodes base58 string using custom alphabet
pub fn decode_walpha(str string, alphabet Alphabet) ?string {
if str.len == 0 {
// decode_bytes decodes the base58 encoded input array, using the Bitcoin alphabet
pub fn decode_bytes(input []u8) ?[]u8 {
return decode_walpha_bytes(input, btc_alphabet)
}
// decode_walpha decodes the base58 encoded input string, using custom alphabet
pub fn decode_walpha(input string, alphabet Alphabet) ?string {
if input.len == 0 {
return ''
}
bin := input.bytes()
res := decode_walpha_bytes(bin, alphabet)?
return res.bytestr()
}
// decode_walpha_bytes decodes the base58 encoded input array using a custom alphabet
pub fn decode_walpha_bytes(input []u8, alphabet Alphabet) ?[]u8 {
if input.len == 0 {
return []
}
zero := alphabet.encode[0]
b58sz := str.len
b58sz := input.len
mut zcount := 0
for i := 0; i < b58sz && str[i] == zero; i++ {
for i := 0; i < b58sz && input[i] == zero; i++ {
zcount++
}
@ -134,7 +161,7 @@ pub fn decode_walpha(str string, alphabet Alphabet) ?string {
mut binu := []u8{len: 2 * ((b58sz * 406 / 555) + 1)}
mut outi := []u32{len: (b58sz + 3) / 4}
for _, r in str {
for _, r in input {
if r > 127 {
panic(@MOD + '.' + @FN +
': high-bit set on invalid digit; outside of ascii range ($r). This should never happen.')
@ -172,10 +199,10 @@ pub fn decode_walpha(str string, alphabet Alphabet) ?string {
// find the most significant byte post-decode, if any
for msb := zcount; msb < binu.len; msb++ { // loop relies on u32 overflow
if binu[msb] > 0 {
return binu[msb - zcount..out_len].bytestr()
return binu[msb - zcount..out_len]
}
}
// it's all zeroes
return binu[..out_len].bytestr()
return binu[..out_len]
}

View File

@ -0,0 +1,42 @@
import encoding.base58
import encoding.hex
fn test_encode() ? {
for input, expected in {
'': ''
'6263': '2PMCRQ'
'hello world': 'StV1DL6CwTryKyV'
'\x00\x00hello world': '11StV1DL6CwTryKyV'
} {
output := base58.encode(input)
println('> input: `$input` | $input.bytes().hex() | => output: `$output`')
assert output == expected
}
}
fn test_encode_int() ? {
for input, expected in {
0x6263: '8VG'
0x61: '2g'
0x626262: 'a3gV'
0x636363: 'aPEr'
} {
output := base58.encode_int(input)?
println('> input: 0x${input:x} | => output: `$output`')
assert output == expected
}
}
fn test_decode() ? {
for output, expected in {
'USm3fpXnKG5EUBx2ndxBDMPVciP5hGey2Jh4NDv6gmeo1LkMeiKrLJUUBk6Z': 'The quick brown fox jumps over the lazy dog.'
'11StV1DL6CwTryKyV': '\x00\x00hello world'
'2NEpo7TZRRrLZSi2U': 'Hello World!'
'14cxpo3MBCYYWCgF74SWTdcmxipnGUsPw3': hex.decode('0027b5891b01da2db74cde1689a97a2acbe23d5fb1c0205bf6')?.bytestr()
'3vQB7B6MrGQZaxCuFg4oh': hex.decode('68656c6c6f20776f726c64bc62d4b8')?.bytestr()
} {
input := base58.decode(output)?
println('> output: `$output` | decoded input: `$input` | bytes: $input.bytes().hex()')
assert input.bytes().hex() == expected.bytes().hex()
}
}