11package io .ipfs .multibase ;
22
3- /**
3+ /*
44 * Copyright 2011 Google Inc.
5+ * Copyright 2018 Andreas Schildbach
6+ *
7+ * From https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/core/Base58.java
58 *
69 * Licensed under the Apache License, Version 2.0 (the "License");
710 * you may not use this file except in compliance with the License.
1720 */
1821
1922import java .math .BigInteger ;
23+ import java .util .Arrays ;
2024
2125/**
22- * A custom form of base58 is used to encode BitCoin addresses. Note that this is not the same base58 as used by
23- * Flickr, which you may see reference to around the internet. <p>
24- *
25- * Satoshi says: why base-58 instead of standard base-64 encoding? <p>
26- *
26+ * Base58 is a way to encode Bitcoin addresses (or arbitrary data) as alphanumeric strings.
27+ * <p>
28+ * Note that this is not the same base58 as used by Flickr, which you may find referenced around the Internet.
29+ * <p>
30+ * Satoshi explains: why base-58 instead of standard base-64 encoding?
2731 * <ul>
2832 * <li>Don't want 0OIl characters that look the same in some fonts and
29- * could be used to create visually identical looking account numbers.</li>
33+ * could be used to create visually identical looking account numbers.</li>
3034 * <li>A string with non-alphanumeric characters is not as easily accepted as an account number.</li>
3135 * <li>E-mail usually won't line-break if there's no punctuation to break at.</li>
3236 * <li>Doubleclicking selects the whole number as one word if it's all alphanumeric.</li>
3337 * </ul>
38+ * <p>
39+ * However, note that the encoding/decoding runs in O(n²) time, so it is not useful for large data.
40+ * <p>
41+ * The basic idea of the encoding is to treat the data bytes as a large number represented using
42+ * base-256 digits, convert the number to be represented using base-58 digits, preserve the exact
43+ * number of leading zeros (which are otherwise lost during the mathematical operations on the
44+ * numbers), and finally represent the resulting base-58 digits as alphanumeric ASCII characters.
3445 */
3546public class Base58 {
36- private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" ;
37- private static final BigInteger BASE = BigInteger .valueOf (58 );
47+ public static final char [] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" .toCharArray ();
48+ private static final char ENCODED_ZERO = ALPHABET [0 ];
49+ private static final int [] INDEXES = new int [128 ];
50+ static {
51+ Arrays .fill (INDEXES , -1 );
52+ for (int i = 0 ; i < ALPHABET .length ; i ++) {
53+ INDEXES [ALPHABET [i ]] = i ;
54+ }
55+ }
56+
57+ /**
58+ * Encodes the given bytes as a base58 string (no checksum is appended).
59+ *
60+ * @param input the bytes to encode
61+ * @return the base58-encoded string
62+ */
63+ public static String encode (byte [] input ) {
64+ if (input .length == 0 ) {
65+ return "" ;
66+ }
67+ // Count leading zeros.
68+ int zeros = 0 ;
69+ while (zeros < input .length && input [zeros ] == 0 ) {
70+ ++zeros ;
71+ }
72+ // Convert base-256 digits to base-58 digits (plus conversion to ASCII characters)
73+ input = Arrays .copyOf (input , input .length ); // since we modify it in-place
74+ char [] encoded = new char [input .length * 2 ]; // upper bound
75+ int outputStart = encoded .length ;
76+ for (int inputStart = zeros ; inputStart < input .length ; ) {
77+ encoded [--outputStart ] = ALPHABET [divmod (input , inputStart , 256 , 58 )];
78+ if (input [inputStart ] == 0 ) {
79+ ++inputStart ; // optimization - skip leading zeros
80+ }
81+ }
82+ // Preserve exactly as many leading encoded zeros in output as there were leading zeros in input.
83+ while (outputStart < encoded .length && encoded [outputStart ] == ENCODED_ZERO ) {
84+ ++outputStart ;
85+ }
86+ while (--zeros >= 0 ) {
87+ encoded [--outputStart ] = ENCODED_ZERO ;
88+ }
89+ // Return encoded string (including encoded leading zeros).
90+ return new String (encoded , outputStart , encoded .length - outputStart );
91+ }
92+
93+ /**
94+ * Decodes the given base58 string into the original data bytes.
95+ *
96+ * @param input the base58-encoded string to decode
97+ * @return the decoded data bytes
98+ */
99+ public static byte [] decode (String input ) {
100+ if (input .length () == 0 ) {
101+ return new byte [0 ];
102+ }
103+ // Convert the base58-encoded ASCII chars to a base58 byte sequence (base58 digits).
104+ byte [] input58 = new byte [input .length ()];
105+ for (int i = 0 ; i < input .length (); ++i ) {
106+ char c = input .charAt (i );
107+ int digit = c < 128 ? INDEXES [c ] : -1 ;
108+ if (digit < 0 ) {
109+ throw new IllegalStateException ("InvalidCharacter in base 58" );
110+ }
111+ input58 [i ] = (byte ) digit ;
112+ }
113+ // Count leading zeros.
114+ int zeros = 0 ;
115+ while (zeros < input58 .length && input58 [zeros ] == 0 ) {
116+ ++zeros ;
117+ }
118+ // Convert base-58 digits to base-256 digits.
119+ byte [] decoded = new byte [input .length ()];
120+ int outputStart = decoded .length ;
121+ for (int inputStart = zeros ; inputStart < input58 .length ; ) {
122+ decoded [--outputStart ] = divmod (input58 , inputStart , 58 , 256 );
123+ if (input58 [inputStart ] == 0 ) {
124+ ++inputStart ; // optimization - skip leading zeros
125+ }
126+ }
127+ // Ignore extra leading zeroes that were added during the calculation.
128+ while (outputStart < decoded .length && decoded [outputStart ] == 0 ) {
129+ ++outputStart ;
130+ }
131+ // Return decoded data (including original number of leading zeros).
132+ return Arrays .copyOfRange (decoded , outputStart - zeros , decoded .length );
133+ }
38134
39- public static String encode ( final byte [] input ) {
40- return BaseN . encode ( ALPHABET , BASE , input );
135+ public static BigInteger decodeToBigInteger ( String input ) {
136+ return new BigInteger ( 1 , decode ( input ) );
41137 }
42138
43- public static byte [] decode (final String input ) {
44- return BaseN .decode (ALPHABET , BASE , input );
139+ /**
140+ * Divides a number, represented as an array of bytes each containing a single digit
141+ * in the specified base, by the given divisor. The given number is modified in-place
142+ * to contain the quotient, and the return value is the remainder.
143+ *
144+ * @param number the number to divide
145+ * @param firstDigit the index within the array of the first non-zero digit
146+ * (this is used for optimization by skipping the leading zeros)
147+ * @param base the base in which the number's digits are represented (up to 256)
148+ * @param divisor the number to divide by (up to 256)
149+ * @return the remainder of the division operation
150+ */
151+ private static byte divmod (byte [] number , int firstDigit , int base , int divisor ) {
152+ // this is just long division which accounts for the base of the input digits
153+ int remainder = 0 ;
154+ for (int i = firstDigit ; i < number .length ; i ++) {
155+ int digit = (int ) number [i ] & 0xFF ;
156+ int temp = remainder * base + digit ;
157+ number [i ] = (byte ) (temp / divisor );
158+ remainder = temp % divisor ;
159+ }
160+ return (byte ) remainder ;
45161 }
46- }
162+ }
0 commit comments