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  }