base58.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Package mhayaBase58 file from https://github.com/akamensky/base58/blob/master/base58.go
  2. package mhayaBase58
  3. import (
  4. "fmt"
  5. "math/big"
  6. )
  7. var (
  8. bigIntermediateRadix = big.NewInt(430804206899405824) // 58**10
  9. alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
  10. b58table = [256]byte{
  11. 255, 255, 255, 255, 255, 255, 255, 255,
  12. 255, 255, 255, 255, 255, 255, 255, 255,
  13. 255, 255, 255, 255, 255, 255, 255, 255,
  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, 0, 1, 2, 3, 4, 5, 6,
  18. 7, 8, 255, 255, 255, 255, 255, 255,
  19. 255, 9, 10, 11, 12, 13, 14, 15,
  20. 16, 255, 17, 18, 19, 20, 21, 255,
  21. 22, 23, 24, 25, 26, 27, 28, 29,
  22. 30, 31, 32, 255, 255, 255, 255, 255,
  23. 255, 33, 34, 35, 36, 37, 38, 39,
  24. 40, 41, 42, 43, 255, 44, 45, 46,
  25. 47, 48, 49, 50, 51, 52, 53, 54,
  26. 55, 56, 57, 255, 255, 255, 255, 255,
  27. 255, 255, 255, 255, 255, 255, 255, 255,
  28. 255, 255, 255, 255, 255, 255, 255, 255,
  29. 255, 255, 255, 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. }
  44. )
  45. // Encode takes a slice of bytes and encodes it to base58 string.
  46. // Leading zero bytes are kept in place for precise decoding.
  47. func Encode(input []byte) string {
  48. output := make([]byte, 0)
  49. num := new(big.Int).SetBytes(input)
  50. mod := new(big.Int)
  51. var primitiveNum int64
  52. for num.Sign() > 0 {
  53. num.DivMod(num, bigIntermediateRadix, mod)
  54. primitiveNum = mod.Int64()
  55. // This inner loop reduces the amount of calculations with
  56. // *big.Int by doing them with int64. This improves performance.
  57. for i := 0; (num.Sign() > 0 || primitiveNum > 0) && i < 10; i++ {
  58. output = append(output, alphabet[primitiveNum%58])
  59. primitiveNum /= 58
  60. }
  61. }
  62. for i := 0; i < len(input) && input[i] == 0; i++ {
  63. output = append(output, alphabet[0])
  64. }
  65. // Revert byte order:
  66. for i := 0; i < len(output)/2; i++ {
  67. output[i], output[len(output)-1-i] = output[len(output)-1-i], output[i]
  68. }
  69. return string(output)
  70. }
  71. // Decode takes string as an input and returns decoded string and error
  72. // If provided string contains characters illegal for base58 the returned error will be <notnil>
  73. func Decode(input string) (output []byte, err error) {
  74. result := big.NewInt(0)
  75. tmpBig := new(big.Int)
  76. for i := 0; i < len(input); {
  77. var a, m int64 = 0, 58
  78. // This inner loop reduces the amount of calculations with
  79. // *big.Int by doing them with int64. This improves performance.
  80. for f := true; i < len(input) && (f || i%10 != 0); i++ {
  81. tmp := b58table[input[i]]
  82. if tmp == 255 {
  83. msg := "invalid Base58 input string at character \"%c\", position %d"
  84. return output, fmt.Errorf(msg, input[i], i)
  85. }
  86. a = a*58 + int64(tmp)
  87. if !f {
  88. m *= 58
  89. }
  90. f = false
  91. }
  92. result.Mul(result, tmpBig.SetInt64(m))
  93. result.Add(result, tmpBig.SetInt64(a))
  94. }
  95. tmpBytes := result.Bytes()
  96. var numZeros int
  97. for numZeros = 0; numZeros < len(input); numZeros++ {
  98. if input[numZeros] != '1' {
  99. break
  100. }
  101. }
  102. length := numZeros + len(tmpBytes)
  103. output = make([]byte, length)
  104. copy(output[numZeros:], tmpBytes)
  105. return
  106. }