frostfs-crypto/wif.go

63 lines
1.6 KiB
Go

package crypto
import (
"bytes"
"crypto/ecdsa"
"crypto/sha256"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-crypto/internal"
"github.com/mr-tron/base58"
)
const (
// WIFLength constant length of WIF string.
WIFLength = 38
// ErrBadWIF when passed WIF-string could not be decoded from base58.
ErrBadWIF = internal.Error("bad wif")
// ErrBadChecksum when passed WIF-string could not be verified
// by last 4 bytes signature.
ErrBadChecksum = internal.Error("bad checksum")
// ErrEmptyPrivateKey when PK passed into WIFEncode method is nil.
ErrEmptyPrivateKey = internal.Error("empty private key")
)
func wifCheckSum(data []byte) []byte {
sum := sha256.Sum256(data)
sum = sha256.Sum256(sum[:])
return sum[:4]
}
// WIFEncode encodes the given private key into a WIF string.
func WIFEncode(key *ecdsa.PrivateKey) (string, error) {
if key == nil || key.D == nil {
return "", ErrEmptyPrivateKey
}
data := make([]byte, WIFLength)
data[0] = 0x80
data[33] = 0x01
copy(data[1:33], key.D.Bytes())
copy(data[34:], wifCheckSum(data[:34]))
return base58.Encode(data), nil
}
// WIFDecode decoded the given WIF string into a private key.
func WIFDecode(wif string) (*ecdsa.PrivateKey, error) {
data, err := base58.Decode(wif)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrBadWIF, err)
} else if actual := len(data); actual != WIFLength {
return nil, fmt.Errorf("%w: expect: %d, actual: %d", ErrBadWIF, WIFLength, actual)
} else if sum := wifCheckSum(data[:34]); !bytes.Equal(data[34:], sum) {
return nil, ErrBadChecksum
}
return UnmarshalPrivateKey(data[1:33])
}