github.com/yaling888/clash@v1.53.0/common/encoding/base58/base58.go (about) 1 package base58 2 3 import ( 4 "math/big" 5 ) 6 7 const ( 8 alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" 9 10 alphabetIdx0 = '1' 11 ) 12 13 var b58 = [256]byte{ 14 255, 255, 255, 255, 255, 255, 255, 255, 15 255, 255, 255, 255, 255, 255, 255, 255, 16 255, 255, 255, 255, 255, 255, 255, 255, 17 255, 255, 255, 255, 255, 255, 255, 255, 18 255, 255, 255, 255, 255, 255, 255, 255, 19 255, 255, 255, 255, 255, 255, 255, 255, 20 255, 0, 1, 2, 3, 4, 5, 6, 21 7, 8, 255, 255, 255, 255, 255, 255, 22 255, 9, 10, 11, 12, 13, 14, 15, 23 16, 255, 17, 18, 19, 20, 21, 255, 24 22, 23, 24, 25, 26, 27, 28, 29, 25 30, 31, 32, 255, 255, 255, 255, 255, 26 255, 33, 34, 35, 36, 37, 38, 39, 27 40, 41, 42, 43, 255, 44, 45, 46, 28 47, 48, 49, 50, 51, 52, 53, 54, 29 55, 56, 57, 255, 255, 255, 255, 255, 30 255, 255, 255, 255, 255, 255, 255, 255, 31 255, 255, 255, 255, 255, 255, 255, 255, 32 255, 255, 255, 255, 255, 255, 255, 255, 33 255, 255, 255, 255, 255, 255, 255, 255, 34 255, 255, 255, 255, 255, 255, 255, 255, 35 255, 255, 255, 255, 255, 255, 255, 255, 36 255, 255, 255, 255, 255, 255, 255, 255, 37 255, 255, 255, 255, 255, 255, 255, 255, 38 255, 255, 255, 255, 255, 255, 255, 255, 39 255, 255, 255, 255, 255, 255, 255, 255, 40 255, 255, 255, 255, 255, 255, 255, 255, 41 255, 255, 255, 255, 255, 255, 255, 255, 42 255, 255, 255, 255, 255, 255, 255, 255, 43 255, 255, 255, 255, 255, 255, 255, 255, 44 255, 255, 255, 255, 255, 255, 255, 255, 45 255, 255, 255, 255, 255, 255, 255, 255, 46 } 47 48 var bigRadix = [...]*big.Int{ 49 big.NewInt(0), 50 big.NewInt(58), 51 big.NewInt(58 * 58), 52 big.NewInt(58 * 58 * 58), 53 big.NewInt(58 * 58 * 58 * 58), 54 big.NewInt(58 * 58 * 58 * 58 * 58), 55 big.NewInt(58 * 58 * 58 * 58 * 58 * 58), 56 big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58), 57 big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58), 58 big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58), 59 bigRadix10, 60 } 61 62 var bigRadix10 = big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58) // 58^10 63 64 // Decode decodes a modified base58 string to a byte slice. 65 func Decode(b string) []byte { 66 answer := big.NewInt(0) 67 scratch := new(big.Int) 68 69 // Calculating with big.Int is slow for each iteration. 70 // x += b58[b[i]] * j 71 // j *= 58 72 // 73 // Instead we can try to do as many calculations on int64. 74 // We can represent a 10 digit base58 number using an int64. 75 // 76 // Hence, we'll try to convert 10, base58 digits at a time. 77 // The rough idea is to calculate `t`, such that: 78 // 79 // t := b58[b[i+9]] * 58^9 ... + b58[b[i+1]] * 58^1 + b58[b[i]] * 58^0 80 // x *= 58^10 81 // x += t 82 // 83 // Of course, in addition, we'll need to handle boundary condition when `b` is not multiple of 58^10. 84 // In that case we'll use the bigRadix[n] lookup for the appropriate power. 85 for t := b; len(t) > 0; { 86 n := len(t) 87 if n > 10 { 88 n = 10 89 } 90 91 total := uint64(0) 92 for _, v := range t[:n] { 93 if v > 255 { 94 return []byte("") 95 } 96 97 tmp := b58[v] 98 if tmp == 255 { 99 return []byte("") 100 } 101 total = total*58 + uint64(tmp) 102 } 103 104 answer.Mul(answer, bigRadix[n]) 105 scratch.SetUint64(total) 106 answer.Add(answer, scratch) 107 108 t = t[n:] 109 } 110 111 tmpval := answer.Bytes() 112 113 var numZeros int 114 for numZeros = 0; numZeros < len(b); numZeros++ { 115 if b[numZeros] != alphabetIdx0 { 116 break 117 } 118 } 119 flen := numZeros + len(tmpval) 120 val := make([]byte, flen) 121 copy(val[numZeros:], tmpval) 122 123 return val 124 } 125 126 // Encode encodes a byte slice to a modified base58 string. 127 func Encode(b []byte) string { 128 x := new(big.Int) 129 x.SetBytes(b) 130 131 // maximum length of output is log58(2^(8*len(b))) == len(b) * 8 / log(58) 132 maxlen := int(float64(len(b))*1.365658237309761) + 1 133 answer := make([]byte, 0, maxlen) 134 mod := new(big.Int) 135 for x.Sign() > 0 { 136 // Calculating with big.Int is slow for each iteration. 137 // x, mod = x / 58, x % 58 138 // 139 // Instead we can try to do as many calculations on int64. 140 // x, mod = x / 58^10, x % 58^10 141 // 142 // Which will give us mod, which is 10 digit base58 number. 143 // We'll loop that 10 times to convert to the answer. 144 145 x.DivMod(x, bigRadix10, mod) 146 if x.Sign() == 0 { 147 // When x = 0, we need to ensure we don't add any extra zeros. 148 m := mod.Int64() 149 for m > 0 { 150 answer = append(answer, alphabet[m%58]) 151 m /= 58 152 } 153 } else { 154 m := mod.Int64() 155 for i := 0; i < 10; i++ { 156 answer = append(answer, alphabet[m%58]) 157 m /= 58 158 } 159 } 160 } 161 162 // leading zero bytes 163 for _, i := range b { 164 if i != 0 { 165 break 166 } 167 answer = append(answer, alphabetIdx0) 168 } 169 170 // reverse 171 alen := len(answer) 172 for i := 0; i < alen/2; i++ { 173 answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i] 174 } 175 176 return string(answer) 177 }