github.com/turingchain2020/turingchain@v1.1.21/wallet/bipwallet/basen/basen.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Copyright (c) 2014 Casey Marshall. See LICENSE file for details. 6 7 // Package basen basen (base-N) is a simple Go encoding package for representing bytes as big integers in arbitrary base-N encoding. 8 package basen 9 10 import ( 11 "crypto/rand" 12 "fmt" 13 "math/big" 14 "unicode/utf8" 15 ) 16 17 var zero = big.NewInt(int64(0)) 18 19 // Encoding represents a given base-N encoding. 20 type Encoding struct { 21 alphabet string 22 index map[byte]*big.Int 23 base *big.Int 24 } 25 26 const base62Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 27 28 // Base62 represents bytes as a base-62 number [0-9A-Za-z]. 29 var Base62 = NewEncoding(base62Alphabet) 30 31 const base58Alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" 32 33 // Base58 represents bytes as a base-58 number [1-9A-GHJ-LM-Za-z]. 34 var Base58 = NewEncoding(base58Alphabet) 35 36 // NewEncoding creates a new base-N representation from the given alphabet. 37 // Panics if the alphabet is not unique. Only ASCII characters are supported. 38 func NewEncoding(alphabet string) *Encoding { 39 return &Encoding{ 40 alphabet: alphabet, 41 index: newAlphabetMap(alphabet), 42 base: big.NewInt(int64(len(alphabet))), 43 } 44 } 45 46 func newAlphabetMap(s string) map[byte]*big.Int { 47 if utf8.RuneCountInString(s) != len(s) { 48 panic("multi-byte characters not supported") 49 } 50 result := make(map[byte]*big.Int) 51 for i := range s { 52 result[s[i]] = big.NewInt(int64(i)) 53 } 54 if len(result) != len(s) { 55 panic("alphabet contains non-unique characters") 56 } 57 return result 58 } 59 60 // Random returns the base-encoded representation of n random bytes. 61 func (enc *Encoding) Random(n int) (string, error) { 62 buf := make([]byte, n) 63 _, err := rand.Reader.Read(buf) 64 if err != nil { 65 return "", err 66 } 67 return enc.EncodeToString(buf), nil 68 } 69 70 // MustRandom returns the base-encoded representation of n random bytes, 71 // panicking in the unlikely event of a read error from the random source. 72 func (enc *Encoding) MustRandom(n int) string { 73 s, err := enc.Random(n) 74 if err != nil { 75 panic(err) 76 } 77 return s 78 } 79 80 // Base returns the number base of the encoding. 81 func (enc *Encoding) Base() int { 82 return len(enc.alphabet) 83 } 84 85 // EncodeToString returns the base-encoded string representation 86 // of the given bytes. 87 func (enc *Encoding) EncodeToString(b []byte) string { 88 n := new(big.Int) 89 r := new(big.Int) 90 n.SetBytes(b) 91 var result []byte 92 for n.Cmp(zero) > 0 { 93 n, r = n.DivMod(n, enc.base, r) 94 result = append([]byte{enc.alphabet[r.Int64()]}, result...) 95 } 96 return string(result) 97 } 98 99 // DecodeString returns the bytes for the given base-encoded string. 100 func (enc *Encoding) DecodeString(s string) ([]byte, error) { 101 result := new(big.Int) 102 for i := range s { 103 n, ok := enc.index[s[i]] 104 if !ok { 105 return nil, fmt.Errorf("invalid character %q at index %d", s[i], i) 106 } 107 result = result.Add(result.Mul(result, enc.base), n) 108 } 109 return result.Bytes(), nil 110 } 111 112 // DecodeStringN returns N bytes for the given base-encoded string. 113 // Use this method to ensure the value is left-padded with zeroes. 114 func (enc *Encoding) DecodeStringN(s string, n int) ([]byte, error) { 115 value, err := enc.DecodeString(s) 116 if err != nil { 117 return nil, err 118 } 119 if len(value) > n { 120 return nil, fmt.Errorf("value is too large") 121 } 122 pad := make([]byte, n-len(value)) 123 return append(pad, value...), nil 124 }