func TestBase58(t *testing.T) { // Encode tests for x, test := range stringTests { tmp := []byte(test.in) if res := base58.Encode(tmp); res != test.out { t.Errorf("Encode test #%d failed: got: %s want: %s", x, res, test.out) continue } } // Decode tests for x, test := range hexTests { b, err := hex.DecodeString(test.in) if err != nil { t.Errorf("hex.DecodeString failed failed #%d: got: %s", x, test.in) continue } if res := base58.Decode(test.out); bytes.Equal(res, b) != true { t.Errorf("Decode test #%d failed: got: %q want: %q", x, res, test.in) continue } } // Decode with invalid input for x, test := range invalidStringTests { if res := base58.Decode(test.in); string(res) != test.out { t.Errorf("Decode invalidString test #%d failed: got: %q want: %q", x, res, test.out) continue } } }
// This example demonstrates how to decode modified base58 encoded data. func ExampleDecode() { // Decode example modified base58 encoded data. encoded := "25JnwSn7XKfNQ" decoded := base58.Decode(encoded) // Show the decoded data. fmt.Println("Decoded Data:", string(decoded)) // Output: // Decoded Data: Test data }
func BenchmarkBase58Decode(b *testing.B) { b.StopTimer() data := bytes.Repeat([]byte{0xff}, 5000) encoded := base58.Encode(data) b.SetBytes(int64(len(encoded))) b.StartTimer() for i := 0; i < b.N; i++ { base58.Decode(encoded) } }
// NewKeyFromString returns a new extended key instance from a base58-encoded // extended key. func NewKeyFromString(key string) (*ExtendedKey, error) { // The base58-decoded extended key must consist of a serialized payload // plus an additional 4 bytes for the checksum. decoded := base58.Decode(key) if len(decoded) != serializedKeyLen+4 { return nil, ErrInvalidKeyLen } // The serialized format is: // version (4) || depth (1) || parent fingerprint (4)) || // child num (4) || chain code (32) || key data (33) || checksum (4) // Split the payload and checksum up and ensure the checksum matches. payload := decoded[:len(decoded)-4] checkSum := decoded[len(decoded)-4:] expectedCheckSum := chainhash.HashFuncB(chainhash.HashFuncB(payload))[:4] if !bytes.Equal(checkSum, expectedCheckSum) { return nil, ErrBadChecksum } // Deserialize each of the payload fields. version := payload[:4] depth := uint16(payload[4:5][0]) parentFP := payload[5:9] childNum := binary.BigEndian.Uint32(payload[9:13]) chainCode := payload[13:45] keyData := payload[45:78] // The key data is a private key if it starts with 0x00. Serialized // compressed pubkeys either start with 0x02 or 0x03. isPrivate := keyData[0] == 0x00 if isPrivate { // Ensure the private key is valid. It must be within the range // of the order of the secp256k1 curve and not be 0. keyData = keyData[1:] keyNum := new(big.Int).SetBytes(keyData) if keyNum.Cmp(chainec.Secp256k1.GetN()) >= 0 || keyNum.Sign() == 0 { return nil, ErrUnusableSeed } } else { // Ensure the public key parses correctly and is actually on the // secp256k1 curve. _, err := chainec.Secp256k1.ParsePubKey(keyData) if err != nil { return nil, err } } return newExtendedKey(version, keyData, chainCode, parentFP, depth, childNum, isPrivate), nil }
// DecodeWIF creates a new WIF structure by decoding the string encoding of // the import format. // // The WIF string must be a base58-encoded string of the following byte // sequence: // // * 2 bytes to identify the network, must be 0x80 for mainnet or 0xef for testnet // * 1 byte for ECDSA type // * 32 bytes of a binary-encoded, big-endian, zero-padded private key // * 4 bytes of checksum, must equal the first four bytes of the double SHA256 // of every byte before the checksum in this sequence // // If the base58-decoded byte sequence does not match this, DecodeWIF will // return a non-nil error. ErrMalformedPrivateKey is returned when the WIF // is of an impossible length. ErrChecksumMismatch is returned if the // expected WIF checksum does not match the calculated checksum. func DecodeWIF(wif string) (*WIF, error) { decoded := base58.Decode(wif) decodedLen := len(decoded) if decodedLen != 39 { return nil, ErrMalformedPrivateKey } // Checksum is first four bytes of hash of the identifier byte // and privKey. Verify this matches the final 4 bytes of the decoded // private key. cksum := chainhash.HashFuncB(decoded[:decodedLen-4]) if !bytes.Equal(cksum[:4], decoded[decodedLen-4:]) { return nil, ErrChecksumMismatch } netID := [2]byte{decoded[0], decoded[1]} var privKey chainec.PrivateKey ecType := 0 switch int(decoded[2]) { case chainec.ECTypeSecp256k1: privKeyBytes := decoded[3 : 3+chainec.Secp256k1.PrivKeyBytesLen()] privKey, _ = chainec.Secp256k1.PrivKeyFromScalar(privKeyBytes) ecType = chainec.ECTypeSecp256k1 case chainec.ECTypeEdwards: privKeyBytes := decoded[3 : 3+32] privKey, _ = chainec.Edwards.PrivKeyFromScalar(privKeyBytes) ecType = chainec.ECTypeEdwards case chainec.ECTypeSecSchnorr: privKeyBytes := decoded[3 : 3+chainec.SecSchnorr.PrivKeyBytesLen()] privKey, _ = chainec.SecSchnorr.PrivKeyFromScalar(privKeyBytes) ecType = chainec.ECTypeSecSchnorr } return &WIF{ecType, privKey, netID}, nil }
// TstAddressSAddr returns the expected script address bytes for // P2PKH and P2SH decred addresses. func TstAddressSAddr(addr string) []byte { decoded := base58.Decode(addr) return decoded[2 : 2+ripemd160.Size] }