Base58Check encoding: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added FreeBASIC)
(This page was neither marked as a task or draft task. It has now been marked as a draft task.)
Line 1: Line 1:
{{draft task}}

[[Category:Encodings]]
[[Category:Encodings]]
[[Category:Checksums]]
[[Category:Checksums]]

Revision as of 23:21, 8 November 2017

Base58Check encoding is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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

Library: GMP

<lang freebasic>' version 14-08-2017 ' compile with: fbc -s console ' uses GMP

  1. 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