Base58Check encoding: Difference between revisions
(→{{header|Haskell}}: and for bulk encoding, there are potentially faster alternatives to linked list subscripting) |
(Added FreeBASIC) |
||
Line 9: | Line 9: | ||
The ''reference algorithm'' is at [https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart the Bitcoin's Base58Check page]. |
The ''reference algorithm'' is at [https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart the Bitcoin's Base58Check page]. |
||
=={{header|FreeBASIC}}== |
|||
{{libheader|GMP}} |
|||
<lang freebasic>' version 14-08-2017 |
|||
' compile with: fbc -s console |
|||
' uses GMP |
|||
#Include Once "gmp.bi" |
|||
Data "25420294593250030202636073700053352635053786165627414518" ' 6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM |
|||
Data "0x61" ' 2g |
|||
Data "0x626262" ' a3gV |
|||
Data "0x636363" ' aPEr |
|||
Data "0x73696d706c792061206c6f6e6720737472696e67" ' 2cFupjhnEsSn59qHXstmK2ffpLv2 |
|||
Data "0x516b6fcd0f" ' ABnLTmg |
|||
Data "0xbf4f89001e670274dd" ' 3SEo3LWLoPntC |
|||
Data "0x572e4794" ' 3EFU7m |
|||
Data "0xecac89cad93923c02321" ' EJDM8drfXA6uyA |
|||
Data "0x10c8511e" ' Rt5zm |
|||
Data "" |
|||
Function conv2base58(decimal As String, _base_ As Integer = 0) As String |
|||
Dim As String convert |
|||
Dim As String base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" |
|||
Dim As String norm58 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv" |
|||
Dim As ZString Ptr gmp_str : gmp_str = Allocate(1000) |
|||
Dim As Mpz_ptr tmp = Allocate(Len(__mpz_struct)) : Mpz_init(tmp) |
|||
Mpz_set_str(tmp, decimal, _base_) |
|||
Mpz_get_str(gmp_str, 58, tmp) |
|||
convert = *gmp_str |
|||
For i As uinteger = 0 To Len(convert) -1 |
|||
convert[i] = base58[InStr(norm58, Chr(convert[i])) -1] |
|||
Next |
|||
Mpz_clear(tmp) : DeAllocate(gmp_str) |
|||
Return convert |
|||
End Function |
|||
' ------=< MAIN >=------ |
|||
Dim As String str_in |
|||
Print "OkobppXBkab(58) --> "; conv2base58("OkobppXBkab", 58) ' 10687460092462769069(10) |
|||
Print |
|||
Do |
|||
Read str_in |
|||
If str_in = "" Then Exit Do |
|||
Print str_in; |
|||
If Len(str_in) < 54 Then Print Tab(43); |
|||
Print " --> "; conv2base58(str_in) |
|||
Loop |
|||
' empty keyboard buffer |
|||
While Inkey <> "" : Wend |
|||
Print : Print "hit any key to end program" |
|||
Sleep |
|||
End</lang> |
|||
{{out}} |
|||
<pre>OkobppXBkab(58) --> RosettaCode |
|||
25420294593250030202636073700053352635053786165627414518 --> 6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM |
|||
0x61 --> 2g |
|||
0x626262 --> a3gV |
|||
0x636363 --> aPEr |
|||
0x73696d706c792061206c6f6e6720737472696e67 --> 2cFupjhnEsSn59qHXstmK2ffpLv2 |
|||
0x516b6fcd0f --> ABnLTmg |
|||
0xbf4f89001e670274dd --> 3SEo3LWLoPntC |
|||
0x572e4794 --> 3EFU7m |
|||
0xecac89cad93923c02321 --> EJDM8drfXA6uyA |
|||
0x10c8511e --> Rt5zm</pre> |
|||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
<lang haskell>import Numeric (showIntAtBase) |
<lang haskell>import Numeric (showIntAtBase) |
Revision as of 20:44, 14 August 2017
The popular encoding of small and medium-sized checksums is base16, that is more compact than usual base10 and is human readable... For checksums resulting in hash digests bigger than ~100 bits, the base16 is too long: base58 is shorter and (when using good alphabet) preserves secure human readability. The most popular alphabet of base58 is the variant used in bitcoin address (see Bitcoin/address validation), so it is the "default base58 alphabet".
Write a program that takes a checksum (resultant hash digest) integer binary representation as argument, and converts (encode it) into base58 with the standard Bitcoin alphabet — which uses an alphabet of the characters 0 .. 9, A ..Z, a .. z, but without the four characters 0, O, I and l.
The reference algorithm is at the Bitcoin's Base58Check page.
FreeBASIC
<lang freebasic>' version 14-08-2017 ' compile with: fbc -s console ' uses GMP
- Include Once "gmp.bi"
Data "25420294593250030202636073700053352635053786165627414518" ' 6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM Data "0x61" ' 2g Data "0x626262" ' a3gV Data "0x636363" ' aPEr Data "0x73696d706c792061206c6f6e6720737472696e67" ' 2cFupjhnEsSn59qHXstmK2ffpLv2 Data "0x516b6fcd0f" ' ABnLTmg Data "0xbf4f89001e670274dd" ' 3SEo3LWLoPntC Data "0x572e4794" ' 3EFU7m Data "0xecac89cad93923c02321" ' EJDM8drfXA6uyA Data "0x10c8511e" ' Rt5zm Data ""
Function conv2base58(decimal As String, _base_ As Integer = 0) As String
Dim As String convert Dim As String base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" Dim As String norm58 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv" Dim As ZString Ptr gmp_str : gmp_str = Allocate(1000) Dim As Mpz_ptr tmp = Allocate(Len(__mpz_struct)) : Mpz_init(tmp)
Mpz_set_str(tmp, decimal, _base_) Mpz_get_str(gmp_str, 58, tmp)
convert = *gmp_str
For i As uinteger = 0 To Len(convert) -1 convert[i] = base58[InStr(norm58, Chr(convert[i])) -1] Next
Mpz_clear(tmp) : DeAllocate(gmp_str)
Return convert
End Function
' ------=< MAIN >=------ Dim As String str_in
Print "OkobppXBkab(58) --> "; conv2base58("OkobppXBkab", 58) ' 10687460092462769069(10) Print
Do
Read str_in If str_in = "" Then Exit Do Print str_in; If Len(str_in) < 54 Then Print Tab(43); Print " --> "; conv2base58(str_in)
Loop
' empty keyboard buffer While Inkey <> "" : Wend Print : Print "hit any key to end program" Sleep End</lang>
- Output:
OkobppXBkab(58) --> RosettaCode 25420294593250030202636073700053352635053786165627414518 --> 6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM 0x61 --> 2g 0x626262 --> a3gV 0x636363 --> aPEr 0x73696d706c792061206c6f6e6720737472696e67 --> 2cFupjhnEsSn59qHXstmK2ffpLv2 0x516b6fcd0f --> ABnLTmg 0xbf4f89001e670274dd --> 3SEo3LWLoPntC 0x572e4794 --> 3EFU7m 0xecac89cad93923c02321 --> EJDM8drfXA6uyA 0x10c8511e --> Rt5zm
Haskell
<lang haskell>import Numeric (showIntAtBase)
chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
base58Encode :: Integer -> String base58Encode n = showIntAtBase 58 (chars !!) n ""
main :: IO () main = mapM_ (putStrLn . base58Encode)
[25420294593250030202636073700053352635053786165627414518, 0x61, 0x626262, 0x636363, 0x73696d706c792061206c6f6e6720737472696e67, 0x516b6fcd0f, 0xbf4f89001e670274dd, 0x572e4794, 0xecac89cad93923c02321, 0x10c8511e]</lang>
- Output:
6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM 2g a3gV aPEr 2cFupjhnEsSn59qHXstmK2ffpLv2 ABnLTmg 3SEo3LWLoPntC 3EFU7m EJDM8drfXA6uyA Rt5zm
and for bulk encoding, Array access would be one of various slightly faster alternatives to recursive subscripting of linked lists: <lang Haskell>import Numeric (showIntAtBase) import Data.Array
base58Codes :: (Num i, Ix i) => Array i Char base58Codes =
listArray (0, 57) "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
base58Encode :: (Show a, Integral a) => a -> String base58Encode n = showIntAtBase 58 (base58Codes !) n ""
main :: IO () main =
mapM_ (putStrLn . base58Encode) [ 25420294593250030202636073700053352635053786165627414518 , 0x61 , 0x626262 , 0x636363 , 0x73696d706c792061206c6f6e6720737472696e67 , 0x516b6fcd0f , 0xbf4f89001e670274dd , 0x572e4794 , 0xecac89cad93923c02321 , 0x10c8511e ]</lang>
- Output:
6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM 2g a3gV aPEr 2cFupjhnEsSn59qHXstmK2ffpLv2 ABnLTmg 3SEo3LWLoPntC 3EFU7m EJDM8drfXA6uyA Rt5zm
Perl 6
<lang perl6>sub encode_Base58 ( Int $x ) {
constant @codes = < 1 2 3 4 5 6 7 8 9 A B C D E F G H J K L M N P Q R S T U V W X Y Z a b c d e f g h i j k m n o p q r s t u v w x y z >;
return @codes[ $x.polymod( 58 xx * ) ].join.flip;
}
my @tests =
25420294593250030202636073700053352635053786165627414518 => '6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM', 0x61 => '2g', 0x626262 => 'a3gV', 0x636363 => 'aPEr', 0x73696d706c792061206c6f6e6720737472696e67 => '2cFupjhnEsSn59qHXstmK2ffpLv2', 0x516b6fcd0f => 'ABnLTmg', 0xbf4f89001e670274dd => '3SEo3LWLoPntC', 0x572e4794 => '3EFU7m', 0xecac89cad93923c02321 => 'EJDM8drfXA6uyA', 0x10c8511e => 'Rt5zm',
use Test; for @tests {
is encode_Base58(.key), .value, "{.key} encodes to {.value}";
} </lang>
REXX
version 1
Following the description in https://www.anintegratedworld.com/how-to-manually-calculate-base58check-encoding/ I get the result expected there. Apart for the leading 1 the program works also for the inputs shown above. <lang rexx>/* REXX */ s="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" Numeric Digits 100 k='00010966776006953D5567439E5E39F86A0D273BEED61967F6'x n=c2d(k) o= Do Until n=0
rem=n//58 n=n%58 o=o||substr(s,rem+1,1) End
o=o||substr(s,1,1) Say reverse(o)</lang>
- Output:
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
version 2
does what the others do <lang rexx>/* REXX */ s="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" Numeric Digits 1000 cnt_ok=0 Call test 'N',25420294593250030202636073700053352635053786165627414518,,
'6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM'
Call test 'X','61'x ,'2g' Call test 'X','626262'x ,'a3gV' Call test 'X','636363'x ,'aPEr' Call test 'X','73696d706c792061206c6f6e6720737472696e67'x,,
'2cFupjhnEsSn59qHXstmK2ffpLv2'
Call test 'X','516b6fcd0f'x ,'ABnLTmg' Call test 'X','bf4f89001e670274dd'x ,'3SEo3LWLoPntC' Call test 'X','572e4794'x ,'3EFU7m' Call test 'X','ecac89cad93923c02321'x ,'EJDM8drfXA6uyA' Call test 'X','10c8511e'x ,'Rt5zm' Call test 'X','10c8511e'x ,'check_error_handlimng' Say cnt_ok 'tests ok' Exit test:
Parse Arg how,k,res If how='X' Then k=c2d(k) o= Do Until k=0 rem=k//58 k=k%58 o=o||substr(s,rem+1,1) End o=reverse(o) If o=res Then cnt_ok+=1 Else Do Say 'expected:' res Say 'found :' o End Return</lang>
- Output:
expected: check_error_handlimng found : Rt5zm 10 tests ok