From 42ebb60bc1acb661739073727003afa9dbef2cdc Mon Sep 17 00:00:00 2001 From: Gede Sukra Widhyawan Date: Tue, 17 Mar 2020 16:22:41 +0800 Subject: [PATCH 1/3] bitcoin sig: add public key into signature --- cmd/transaction/generator.go | 22 ++++-- common/crypto/bitcoinSignature.go | 110 +++++++++++++++++++++--------- common/crypto/ed25519.go | 13 ++++ common/crypto/signature.go | 77 +++++++++++++++++---- common/crypto/signature_test.go | 22 +++--- common/model/signature.pb.go | 89 +++++++++++++++++++++--- 6 files changed, 262 insertions(+), 71 deletions(-) diff --git a/cmd/transaction/generator.go b/cmd/transaction/generator.go index 9c43bd0ae..80d31b42b 100644 --- a/cmd/transaction/generator.go +++ b/cmd/transaction/generator.go @@ -250,13 +250,25 @@ func GenerateBasicTransaction( senderAccountAddress = crypto.NewEd25519Signature().GetAddressFromSeed(senderSeed) case model.SignatureType_BitcoinSignature: var ( - bitcoinSig = crypto.NewBitcoinSignature(crypto.DefaultBitcoinNetworkParams(), crypto.DefaultBitcoinCurve()) - pubKey = bitcoinSig.GetPublicKeyFromSeed(senderSeed, crypto.DefaultBitcoinPublicKeyFormat()) - err error + bitcoinSig = crypto.NewBitcoinSignature(crypto.DefaultBitcoinNetworkParams(), crypto.DefaultBitcoinCurve()) + pubKey, err = bitcoinSig.GetPublicKeyFromSeed( + senderSeed, + crypto.DefaultBitcoinPublicKeyFormat(), + crypto.DefaultBitcoinPrivateKeyLength(), + ) ) - senderAccountAddress, err = bitcoinSig.GetAddressPublicKey(pubKey) if err != nil { - fmt.Println("GenerateBasicTransaction-BitcoinSignature-Failed GetPublicKey") + panic(fmt.Sprintln( + "GenerateBasicTransaction-BitcoinSignature-Failed GetPublicKey", + err.Error(), + )) + } + senderAccountAddress, err = bitcoinSig.GetAddressFromPublicKey(pubKey) + if err != nil { + panic(fmt.Sprintln( + "GenerateBasicTransaction-BitcoinSignature-Failed GetPublicKey", + err.Error(), + )) } default: panic("GenerateBasicTransaction-Invalid Signature Type") diff --git a/common/crypto/bitcoinSignature.go b/common/crypto/bitcoinSignature.go index 4f6479c3e..6e2509e35 100644 --- a/common/crypto/bitcoinSignature.go +++ b/common/crypto/bitcoinSignature.go @@ -1,9 +1,13 @@ package crypto import ( + "hash" + "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" + "github.com/zoobc/zoobc-core/common/blocker" + "github.com/zoobc/zoobc-core/common/model" "golang.org/x/crypto/sha3" ) @@ -30,9 +34,14 @@ func DefaultBitcoinCurve() *btcec.KoblitzCurve { } // DefaultBitcoinPublicKeyFormat return recommended public key format -func DefaultBitcoinPublicKeyFormat() btcutil.PubKeyFormat { +func DefaultBitcoinPublicKeyFormat() model.BitcoinPublicKeyFormat { // https://bitcoin.org/en/glossary/compressed-public-key - return btcutil.PKFCompressed + return model.BitcoinPublicKeyFormat_PublicKeyFormatCompressed +} + +// DefaultBitcoinPrivateKeyLength to +func DefaultBitcoinPrivateKeyLength() model.PrivateKeyBytesLength { + return model.PrivateKeyBytesLength_PrivateKey256Bits } // NewBitcoinSignature is new instance of bitcoin signature @@ -67,36 +76,77 @@ func (b *BitcoinSignature) GetNetworkParams() *chaincfg.Params { } // GetPrivateKeyFromSeed to get private key form seed -func (b *BitcoinSignature) GetPrivateKeyFromSeed(seed string) *btcec.PrivateKey { +func (b *BitcoinSignature) GetPrivateKeyFromSeed( + seed string, + privkeyLength model.PrivateKeyBytesLength, +) (*btcec.PrivateKey, error) { var ( // Convert seed (secret phrase) to byte array seedBuffer = []byte(seed) - // Compute SHA3-256 hash of seed (secret phrase) - seedHash = sha3.Sum256(seedBuffer) - privateKey, _ = btcec.PrivKeyFromBytes(b.Curve, seedHash[:]) + hasher hash.Hash + err error + ) + switch privkeyLength { + case model.PrivateKeyBytesLength_PrivateKey256Bits: + hasher = sha3.New256() + case model.PrivateKeyBytesLength_PrivateKey384Bits: + hasher = sha3.New384() + case model.PrivateKeyBytesLength_PrivateKey512Bits: + hasher = sha3.New512() + default: + return nil, blocker.NewBlocker(blocker.AppErr, "invalidPrivateKeyLength") + } + + _, err = hasher.Write(seedBuffer) + if err != nil { + return nil, blocker.NewBlocker(blocker.AppErr, err.Error()) + } + var ( + privateKey, _ = btcec.PrivKeyFromBytes(b.Curve, hasher.Sum(nil)) ) - return privateKey + return privateKey, nil } // GetPublicKeyFromSeed Get the raw public key corresponding to a seed (secret phrase) +func (b *BitcoinSignature) GetPublicKeyFromSeed( + seed string, + format model.BitcoinPublicKeyFormat, + privkeyLength model.PrivateKeyBytesLength, +) ([]byte, error) { + var privateKey, err = b.GetPrivateKeyFromSeed(seed, privkeyLength) + if err != nil { + return nil, err + } + publicKey, err := b.GetPublicKeyFromPrivateKey(privateKey, format) + if err != nil { + return nil, err + } + return publicKey, nil +} + +// GetPublicKeyFromPrivateKey get raw public key from private key // public key format : https://bitcoin.org/en/wallets-guide#public-key-formats -func (b *BitcoinSignature) GetPublicKeyFromSeed(seed string, format btcutil.PubKeyFormat) []byte { - var privateKey = b.GetPrivateKeyFromSeed(seed) +func (b *BitcoinSignature) GetPublicKeyFromPrivateKey( + privateKey *btcec.PrivateKey, + format model.BitcoinPublicKeyFormat, +) ([]byte, error) { switch format { - case btcutil.PKFUncompressed: - return privateKey.PubKey().SerializeUncompressed() - case btcutil.PKFCompressed: - return privateKey.PubKey().SerializeCompressed() - case btcutil.PKFHybrid: - return privateKey.PubKey().SerializeHybrid() + case model.BitcoinPublicKeyFormat_PublicKeyFormatUncompressed: + return privateKey.PubKey().SerializeUncompressed(), nil + case model.BitcoinPublicKeyFormat_PublicKeyFormatCompressed: + return privateKey.PubKey().SerializeCompressed(), nil default: - return nil + return nil, blocker.NewBlocker(blocker.AppErr, "invalidPublicKeyFormat") } } -// GetAddressPublicKey to get address public key from seed -// NOTE: Currently the address is the hex-encoded from serialized public key (pay-to-pubkey) -func (b *BitcoinSignature) GetAddressPublicKey(publicKey []byte) (string, error) { +// GetPublicKeyFromBytes to get public key from raw bytes public key +func (b *BitcoinSignature) GetPublicKeyFromBytes(pubkey []byte) (*btcec.PublicKey, error) { + return btcec.ParsePubKey(pubkey, b.Curve) +} + +// GetPublicKeyString will return hex string from bytes public key +func (b *BitcoinSignature) GetPublicKeyString(publicKey []byte) (string, error) { var address, err = btcutil.NewAddressPubKey(publicKey, b.GetNetworkParams()) if err != nil { return "", err @@ -104,26 +154,22 @@ func (b *BitcoinSignature) GetAddressPublicKey(publicKey []byte) (string, error) return address.String(), nil } -// GetBytesAddressPublicKey Get raw bytes of address -func (b *BitcoinSignature) GetBytesAddressPublicKey(address string) ([]byte, error) { - var decodedAddress, err = btcutil.DecodeAddress(address, b.GetNetworkParams()) +// GetAddressFromPublicKey to get address public key from seed +func (b *BitcoinSignature) GetAddressFromPublicKey(publicKey []byte) (string, error) { + var address, err = btcutil.NewAddressPubKey(publicKey, b.GetNetworkParams()) if err != nil { - return nil, err + return "", err } - return decodedAddress.ScriptAddress(), nil + return address.EncodeAddress(), nil } -// GetPublicKeyFromAddress to get public key from address -func (b *BitcoinSignature) GetPublicKeyFromAddress(address string) (*btcec.PublicKey, error) { - rowBytesAddress, err := b.GetBytesAddressPublicKey(address) - if err != nil { - return nil, err - } - publicKey, err := btcec.ParsePubKey(rowBytesAddress, b.Curve) +// GetAddressBytes Get raw bytes of address +func (b *BitcoinSignature) GetAddressBytes(address string) ([]byte, error) { + var decodedAddress, err = btcutil.DecodeAddress(address, b.GetNetworkParams()) if err != nil { return nil, err } - return publicKey, nil + return decodedAddress.ScriptAddress(), nil } // GetSignatureFromBytes to get signature type from signature raw bytes diff --git a/common/crypto/ed25519.go b/common/crypto/ed25519.go index 2d687b285..ee4e28f23 100644 --- a/common/crypto/ed25519.go +++ b/common/crypto/ed25519.go @@ -52,6 +52,19 @@ func (es *Ed25519Signature) GetAddressFromSeed(seed string) string { return result } +// GetPublicKeyFromPrivateKey get public key bytes from private key +func (es *Ed25519Signature) GetPublicKeyFromPrivateKey(privateKey []byte) ([]byte, error) { + if len(privateKey) != ed25519.PrivateKeySize { + return nil, blocker.NewBlocker(blocker.ValidationErr, "invalid ed25519 private key") + } + return privateKey[32:], nil +} + +// GetPublicKeyString will return string of row bytes public key +func (*Ed25519Signature) GetPublicKeyString(publicKey []byte) string { + return base64.StdEncoding.EncodeToString(publicKey) +} + // GetPublicKeyFromAddress Get the raw public key from a formatted address func (*Ed25519Signature) GetPublicKeyFromAddress(address string) ([]byte, error) { // decode base64 back to byte diff --git a/common/crypto/signature.go b/common/crypto/signature.go index aaecf05b8..9fa424f86 100644 --- a/common/crypto/signature.go +++ b/common/crypto/signature.go @@ -2,7 +2,6 @@ package crypto import ( "bytes" - "encoding/base64" "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/model" @@ -50,13 +49,28 @@ func (*Signature) Sign(payload []byte, signatureType model.SignatureType, seed s return buffer.Bytes(), nil case model.SignatureType_BitcoinSignature: var ( - bitcoinSignature = NewBitcoinSignature(DefaultBitcoinNetworkParams(), DefaultBitcoinCurve()) - accountPrivateKey = bitcoinSignature.GetPrivateKeyFromSeed(seed) - signature, err = bitcoinSignature.Sign(accountPrivateKey, payload) + bitcoinSignature = NewBitcoinSignature(DefaultBitcoinNetworkParams(), DefaultBitcoinCurve()) + accountPrivateKey, err = bitcoinSignature.GetPrivateKeyFromSeed(seed, DefaultBitcoinPrivateKeyLength()) ) if err != nil { return nil, err } + accountPublicKey, err := bitcoinSignature.GetPublicKeyFromPrivateKey( + accountPrivateKey, + DefaultBitcoinPublicKeyFormat(), + ) + if err != nil { + return nil, err + } + // Add public key into signature bytes + accountPublicKeyLength := util.ConvertUint16ToBytes(uint16(len(accountPublicKey))) + buffer.Write(accountPublicKeyLength) + buffer.Write(accountPublicKey) + signature, err := bitcoinSignature.Sign(accountPrivateKey, payload) + if err != nil { + return nil, err + } + buffer.Write(signature) return buffer.Bytes(), nil default: @@ -107,7 +121,12 @@ func (*Signature) VerifySignature(payload, signature []byte, accountAddress stri case model.SignatureType_BitcoinSignature: // bitcoin var ( bitcoinSignature = NewBitcoinSignature(DefaultBitcoinNetworkParams(), DefaultBitcoinCurve()) - publicKey, err = bitcoinSignature.GetPublicKeyFromAddress(accountAddress) + // 2 bytes after signature type bytes is length of public key + pubKeyFirstBytesIndex = 6 + pubKeyBytesLength = util.ConvertBytesToUint16(signature[4:pubKeyFirstBytesIndex]) + signatureFirstBytesIndex = pubKeyFirstBytesIndex + int(pubKeyBytesLength) + signaturePubKeyBytes = signature[pubKeyFirstBytesIndex:signatureFirstBytesIndex] + signaturePubKey, err = bitcoinSignature.GetPublicKeyFromBytes(signaturePubKeyBytes) ) if err != nil { return blocker.NewBlocker( @@ -115,14 +134,28 @@ func (*Signature) VerifySignature(payload, signature []byte, accountAddress stri err.Error(), ) } - sig, err := bitcoinSignature.GetSignatureFromBytes(signature[4:]) + signaturePubKeyAddress, err := bitcoinSignature.GetAddressFromPublicKey(signaturePubKeyBytes) + if err != nil { + return blocker.NewBlocker( + blocker.ValidationErr, + err.Error(), + ) + } + // check sender account address to address from public key in signature + if accountAddress != signaturePubKeyAddress { + return blocker.NewBlocker( + blocker.ValidationErr, + "invalidAccountAddrressOrSignaturePublicKey", + ) + } + sig, err := bitcoinSignature.GetSignatureFromBytes(signature[signatureFirstBytesIndex:]) if err != nil { return blocker.NewBlocker( blocker.ValidationErr, err.Error(), ) } - if !bitcoinSignature.Verify(payload, sig, publicKey) { + if !bitcoinSignature.Verify(payload, sig, signaturePubKey) { return blocker.NewBlocker( blocker.ValidationErr, "InvalidSignature", @@ -154,19 +187,35 @@ func (*Signature) GenerateAccountFromSeed(signatureType model.SignatureType, see case model.SignatureType_DefaultSignature: var ed25519Signature = NewEd25519Signature() privateKey = ed25519Signature.GetPrivateKeyFromSeed(seed) - publicKey = privateKey[32:] - publickKeyString = base64.StdEncoding.EncodeToString(publicKey) + publicKey = ed25519Signature.GetPublicKeyFromSeed(seed) + publickKeyString = ed25519Signature.GetPublicKeyString(publicKey) address, err = ed25519Signature.GetAddressFromPublicKey(publicKey) if err != nil { return nil, nil, "", "", err } return privateKey, publicKey, publickKeyString, address, nil case model.SignatureType_BitcoinSignature: - var bitcoinSignature = NewBitcoinSignature(DefaultBitcoinNetworkParams(), DefaultBitcoinCurve()) - - privateKey = bitcoinSignature.GetPrivateKeyFromSeed(seed).Serialize() - publicKey = bitcoinSignature.GetPublicKeyFromSeed(seed, DefaultBitcoinPublicKeyFormat()) - address, err = bitcoinSignature.GetAddressPublicKey(publicKey) + var ( + bitcoinSignature = NewBitcoinSignature(DefaultBitcoinNetworkParams(), DefaultBitcoinCurve()) + privKey, err = bitcoinSignature.GetPrivateKeyFromSeed(seed, DefaultBitcoinPrivateKeyLength()) + ) + if err != nil { + return nil, nil, "", "", err + } + privateKey = privKey.Serialize() + publicKey, err = bitcoinSignature.GetPublicKeyFromSeed( + seed, + DefaultBitcoinPublicKeyFormat(), + DefaultBitcoinPrivateKeyLength(), + ) + if err != nil { + return nil, nil, "", "", err + } + address, err = bitcoinSignature.GetAddressFromPublicKey(publicKey) + if err != nil { + return nil, nil, "", "", err + } + publickKeyString, err = bitcoinSignature.GetPublicKeyString(publicKey) if err != nil { return nil, nil, "", "", err } diff --git a/common/crypto/signature_test.go b/common/crypto/signature_test.go index 449bdf40c..8a8d3781c 100644 --- a/common/crypto/signature_test.go +++ b/common/crypto/signature_test.go @@ -58,9 +58,11 @@ func TestSignature_Sign(t *testing.T) { signatureType: model.SignatureType_BitcoinSignature, seed: "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved", }, - want: []byte{1, 0, 0, 0, 48, 68, 2, 32, 90, 19, 249, 248, 141, 2, 142, 176, 69, 131, 63, 122, 227, 255, 114, 26, 116, 34, - 23, 167, 245, 190, 121, 156, 49, 171, 110, 198, 76, 191, 126, 236, 2, 32, 9, 133, 158, 144, 106, 172, 10, 8, 201, - 172, 22, 1, 23, 102, 80, 158, 55, 191, 144, 127, 111, 186, 226, 211, 3, 203, 131, 93, 140, 126, 90, 133}, + want: []byte{1, 0, 0, 0, 33, 0, 3, 82, 247, 192, 243, 36, 207, 71, 90, 3, 103, 220, 47, 115, 64, 15, 13, 59, 186, 231, 45, + 42, 149, 73, 12, 5, 166, 141, 205, 177, 156, 77, 122, 48, 68, 2, 32, 90, 19, 249, 248, 141, 2, 142, 176, 69, 131, 63, 122, + 227, 255, 114, 26, 116, 34, 23, 167, 245, 190, 121, 156, 49, 171, 110, 198, 76, 191, 126, 236, 2, 32, 9, 133, 158, 144, + 106, 172, 10, 8, 201, 172, 22, 1, 23, 102, 80, 158, 55, 191, 144, 127, 111, 186, 226, 211, 3, 203, 131, 93, 140, 126, 90, + 133}, wantErr: false, }, { @@ -146,10 +148,12 @@ func TestSignature_VerifySignature(t *testing.T) { name: "VerifySignature:success-{bitcoin-signature}", args: args{ payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54}, - accountAddress: "0352f7c0f324cf475a0367dc2f73400f0d3bbae72d2a95490c05a68dcdb19c4d7a", - signature: []byte{1, 0, 0, 0, 48, 68, 2, 32, 90, 19, 249, 248, 141, 2, 142, 176, 69, 131, 63, 122, 227, 255, 114, 26, 116, 34, - 23, 167, 245, 190, 121, 156, 49, 171, 110, 198, 76, 191, 126, 236, 2, 32, 9, 133, 158, 144, 106, 172, 10, 8, 201, - 172, 22, 1, 23, 102, 80, 158, 55, 191, 144, 127, 111, 186, 226, 211, 3, 203, 131, 93, 140, 126, 90, 133}, + accountAddress: "12Ea6WAMZhFnfM5kjyfrfykqVWFcaWorQ8", + signature: []byte{1, 0, 0, 0, 33, 0, 3, 82, 247, 192, 243, 36, 207, 71, 90, 3, 103, 220, 47, 115, 64, 15, 13, 59, 186, 231, 45, + 42, 149, 73, 12, 5, 166, 141, 205, 177, 156, 77, 122, 48, 68, 2, 32, 90, 19, 249, 248, 141, 2, 142, 176, 69, 131, 63, 122, + 227, 255, 114, 26, 116, 34, 23, 167, 245, 190, 121, 156, 49, 171, 110, 198, 76, 191, 126, 236, 2, 32, 9, 133, 158, 144, + 106, 172, 10, 8, 201, 172, 22, 1, 23, 102, 80, 158, 55, 191, 144, 127, 111, 186, 226, 211, 3, 203, 131, 93, 140, 126, 90, + 133}, }, want: nil, }, @@ -253,8 +257,8 @@ func TestSignature_GenerateAccountFromSeed(t *testing.T) { 71, 172, 247, 140, 12, 13, 53, 119, 251, 233, 244, 212}, wantPublicKey: []byte{3, 82, 247, 192, 243, 36, 207, 71, 90, 3, 103, 220, 47, 115, 64, 15, 13, 59, 186, 231, 45, 42, 149, 73, 12, 5, 166, 141, 205, 177, 156, 77, 122}, - wantPublickKeyString: "", - wantAddress: "0352f7c0f324cf475a0367dc2f73400f0d3bbae72d2a95490c05a68dcdb19c4d7a", + wantPublickKeyString: "0352f7c0f324cf475a0367dc2f73400f0d3bbae72d2a95490c05a68dcdb19c4d7a", + wantAddress: "12Ea6WAMZhFnfM5kjyfrfykqVWFcaWorQ8", wantErr: false, }, { diff --git a/common/model/signature.pb.go b/common/model/signature.pb.go index b9b488b19..0bfb9386e 100644 --- a/common/model/signature.pb.go +++ b/common/model/signature.pb.go @@ -52,22 +52,89 @@ func (SignatureType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_a69ee5fbbdd37ed5, []int{0} } +// BitcoinPrivateKeyBytesLength represent the length of private key that can use +type PrivateKeyBytesLength int32 + +const ( + PrivateKeyBytesLength_PrivateKeyInvalid PrivateKeyBytesLength = 0 + PrivateKeyBytesLength_PrivateKey256Bits PrivateKeyBytesLength = 32 + PrivateKeyBytesLength_PrivateKey384Bits PrivateKeyBytesLength = 48 + PrivateKeyBytesLength_PrivateKey512Bits PrivateKeyBytesLength = 64 +) + +var PrivateKeyBytesLength_name = map[int32]string{ + 0: "PrivateKeyInvalid", + 32: "PrivateKey256Bits", + 48: "PrivateKey384Bits", + 64: "PrivateKey512Bits", +} + +var PrivateKeyBytesLength_value = map[string]int32{ + "PrivateKeyInvalid": 0, + "PrivateKey256Bits": 32, + "PrivateKey384Bits": 48, + "PrivateKey512Bits": 64, +} + +func (x PrivateKeyBytesLength) String() string { + return proto.EnumName(PrivateKeyBytesLength_name, int32(x)) +} + +func (PrivateKeyBytesLength) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_a69ee5fbbdd37ed5, []int{1} +} + +// BitcoinPublicKeyFormat represent the option of the Bitcoin public key format that can use +// public key format : https://bitcoin.org/en/wallets-guide#public-key-formats +type BitcoinPublicKeyFormat int32 + +const ( + BitcoinPublicKeyFormat_PublicKeyFormatUncompressed BitcoinPublicKeyFormat = 0 + BitcoinPublicKeyFormat_PublicKeyFormatCompressed BitcoinPublicKeyFormat = 1 +) + +var BitcoinPublicKeyFormat_name = map[int32]string{ + 0: "PublicKeyFormatUncompressed", + 1: "PublicKeyFormatCompressed", +} + +var BitcoinPublicKeyFormat_value = map[string]int32{ + "PublicKeyFormatUncompressed": 0, + "PublicKeyFormatCompressed": 1, +} + +func (x BitcoinPublicKeyFormat) String() string { + return proto.EnumName(BitcoinPublicKeyFormat_name, int32(x)) +} + +func (BitcoinPublicKeyFormat) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_a69ee5fbbdd37ed5, []int{2} +} + func init() { proto.RegisterEnum("model.SignatureType", SignatureType_name, SignatureType_value) + proto.RegisterEnum("model.PrivateKeyBytesLength", PrivateKeyBytesLength_name, PrivateKeyBytesLength_value) + proto.RegisterEnum("model.BitcoinPublicKeyFormat", BitcoinPublicKeyFormat_name, BitcoinPublicKeyFormat_value) } func init() { proto.RegisterFile("model/signature.proto", fileDescriptor_a69ee5fbbdd37ed5) } var fileDescriptor_a69ee5fbbdd37ed5 = []byte{ - // 145 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcd, 0xcd, 0x4f, 0x49, - 0xcd, 0xd1, 0x2f, 0xce, 0x4c, 0xcf, 0x4b, 0x2c, 0x29, 0x2d, 0x4a, 0xd5, 0x2b, 0x28, 0xca, 0x2f, - 0xc9, 0x17, 0x62, 0x05, 0x0b, 0x6b, 0x05, 0x71, 0xf1, 0x06, 0xc3, 0x64, 0x42, 0x2a, 0x0b, 0x52, - 0x85, 0x44, 0xb8, 0x04, 0x5c, 0x52, 0xd3, 0x12, 0x4b, 0x73, 0x4a, 0xe0, 0xe2, 0x02, 0x0c, 0x20, - 0x51, 0xa7, 0xcc, 0x92, 0xe4, 0xfc, 0xcc, 0x3c, 0x84, 0x28, 0xa3, 0x90, 0x28, 0x97, 0xa0, 0x6f, - 0x69, 0x4e, 0x49, 0x66, 0x71, 0x66, 0x3a, 0x42, 0x98, 0xc9, 0x49, 0x2b, 0x4a, 0x23, 0x3d, 0xb3, - 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0xbf, 0x2a, 0x3f, 0x3f, 0x29, 0x19, 0x42, 0xea, - 0x26, 0xe7, 0x17, 0xa5, 0xea, 0x27, 0xe7, 0xe7, 0xe6, 0xe6, 0xe7, 0xe9, 0x83, 0xed, 0x4f, 0x62, - 0x03, 0xbb, 0xc6, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x4b, 0x53, 0x54, 0x61, 0xa6, 0x00, 0x00, - 0x00, + // 251 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0xd0, 0x5f, 0x4b, 0xc3, 0x30, + 0x14, 0x05, 0xf0, 0x4d, 0xd0, 0x87, 0x80, 0x50, 0x8b, 0x15, 0x44, 0x44, 0x1f, 0xa5, 0xe0, 0xaa, + 0x9b, 0x13, 0x1f, 0xa5, 0x8a, 0x20, 0x53, 0x18, 0xfe, 0x01, 0xf1, 0xad, 0xcd, 0xae, 0xdd, 0x85, + 0x24, 0xb7, 0x24, 0x37, 0x83, 0xfa, 0xe9, 0xa5, 0x51, 0x57, 0xba, 0x97, 0x3c, 0xfc, 0xce, 0x81, + 0x5c, 0x8e, 0x48, 0x34, 0x2d, 0x40, 0x65, 0x0e, 0x2b, 0x53, 0xb0, 0xb7, 0x30, 0xaa, 0x2d, 0x31, + 0xc5, 0xdb, 0x81, 0xd3, 0x17, 0xb1, 0xfb, 0xfa, 0x9f, 0xbc, 0x35, 0x35, 0xc4, 0xfb, 0x22, 0xba, + 0x87, 0xaf, 0xc2, 0x2b, 0x5e, 0x7b, 0x34, 0x68, 0x35, 0x47, 0x96, 0x84, 0xa6, 0xd3, 0x61, 0x9c, + 0x88, 0xbd, 0x67, 0xaf, 0x18, 0x1d, 0x56, 0x1d, 0x6f, 0xa5, 0x4e, 0x24, 0x73, 0x8b, 0xab, 0x82, + 0x61, 0x06, 0x4d, 0xde, 0x30, 0xb8, 0x27, 0x30, 0x15, 0x2f, 0xdb, 0x7e, 0x17, 0x3c, 0x9a, 0x55, + 0xa1, 0x70, 0x11, 0x0d, 0xfa, 0x3c, 0x9e, 0x5e, 0xe7, 0xc8, 0x2e, 0x3a, 0xed, 0xf3, 0xe4, 0xe6, + 0x2a, 0xf0, 0x45, 0x9f, 0xa7, 0x97, 0xe3, 0xc0, 0xb7, 0xe9, 0x87, 0x38, 0xf8, 0xbb, 0x70, 0xee, + 0x4b, 0x85, 0x72, 0x06, 0xcd, 0x03, 0x59, 0x5d, 0x70, 0x7c, 0x22, 0x8e, 0x36, 0xe8, 0xdd, 0x48, + 0xd2, 0xb5, 0x05, 0xe7, 0xa0, 0xfd, 0xff, 0x58, 0x1c, 0x6e, 0x14, 0xee, 0xba, 0x78, 0x98, 0xa7, + 0x9f, 0x67, 0x15, 0xf2, 0xd2, 0x97, 0x23, 0x49, 0x3a, 0xfb, 0x26, 0x2a, 0xe5, 0xef, 0x7b, 0x2e, + 0xc9, 0x42, 0x26, 0x49, 0x6b, 0x32, 0x59, 0x98, 0xb3, 0xdc, 0x09, 0xe3, 0x4e, 0x7e, 0x02, 0x00, + 0x00, 0xff, 0xff, 0xe7, 0x9e, 0x8a, 0x01, 0x75, 0x01, 0x00, 0x00, } From 3b31be366816780cab4e0b8abef02cf37e7afb93 Mon Sep 17 00:00:00 2001 From: Gede Sukra Widhyawan Date: Wed, 18 Mar 2020 15:55:52 +0800 Subject: [PATCH 2/3] add unit test --- common/crypto/bitcoinSignature.go | 14 +- common/crypto/bitcoinSignature_test.go | 521 +++++++++++++++++++++++++ common/crypto/ed25519.go | 2 +- common/crypto/ed25519_test.go | 76 ++++ 4 files changed, 602 insertions(+), 11 deletions(-) create mode 100644 common/crypto/bitcoinSignature_test.go diff --git a/common/crypto/bitcoinSignature.go b/common/crypto/bitcoinSignature.go index 6e2509e35..514414502 100644 --- a/common/crypto/bitcoinSignature.go +++ b/common/crypto/bitcoinSignature.go @@ -84,7 +84,7 @@ func (b *BitcoinSignature) GetPrivateKeyFromSeed( // Convert seed (secret phrase) to byte array seedBuffer = []byte(seed) hasher hash.Hash - err error + privateKey *btcec.PrivateKey ) switch privkeyLength { case model.PrivateKeyBytesLength_PrivateKey256Bits: @@ -96,14 +96,8 @@ func (b *BitcoinSignature) GetPrivateKeyFromSeed( default: return nil, blocker.NewBlocker(blocker.AppErr, "invalidPrivateKeyLength") } - - _, err = hasher.Write(seedBuffer) - if err != nil { - return nil, blocker.NewBlocker(blocker.AppErr, err.Error()) - } - var ( - privateKey, _ = btcec.PrivKeyFromBytes(b.Curve, hasher.Sum(nil)) - ) + hasher.Write(seedBuffer) + privateKey, _ = btcec.PrivKeyFromBytes(b.Curve, hasher.Sum(nil)) return privateKey, nil } @@ -126,7 +120,7 @@ func (b *BitcoinSignature) GetPublicKeyFromSeed( // GetPublicKeyFromPrivateKey get raw public key from private key // public key format : https://bitcoin.org/en/wallets-guide#public-key-formats -func (b *BitcoinSignature) GetPublicKeyFromPrivateKey( +func (*BitcoinSignature) GetPublicKeyFromPrivateKey( privateKey *btcec.PrivateKey, format model.BitcoinPublicKeyFormat, ) ([]byte, error) { diff --git a/common/crypto/bitcoinSignature_test.go b/common/crypto/bitcoinSignature_test.go new file mode 100644 index 000000000..6c26017b3 --- /dev/null +++ b/common/crypto/bitcoinSignature_test.go @@ -0,0 +1,521 @@ +package crypto + +import ( + "reflect" + "testing" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/chaincfg" + "github.com/zoobc/zoobc-core/common/model" + "golang.org/x/crypto/sha3" +) + +var ( + mockBitcoinSeed = "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved" + mockBitcoinPrivKey32Bytes = sha3.Sum256([]byte(mockBitcoinSeed)) + mockBitcoinPrivKey48Bytes = sha3.Sum384([]byte(mockBitcoinSeed)) + mockBitcoinPrivKey64Bytes = sha3.Sum512([]byte(mockBitcoinSeed)) + mockBitcoinPublicKetBytes = []byte{3, 82, 247, 192, 243, 36, 207, 71, 90, 3, 103, 220, 47, 115, 64, 15, 13, + 59, 186, 231, 45, 42, 149, 73, 12, 5, 166, 141, 205, 177, 156, 77, 122} +) + +func TestNewBitcoinSignature(t *testing.T) { + type args struct { + netParams *chaincfg.Params + curve *btcec.KoblitzCurve + } + tests := []struct { + name string + args args + want *BitcoinSignature + }{ + { + name: "wantSuccess", + args: args{ + netParams: DefaultBitcoinNetworkParams(), + curve: DefaultBitcoinCurve(), + }, + want: &BitcoinSignature{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := NewBitcoinSignature(tt.args.netParams, tt.args.curve); !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewBitcoinSignature() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestBitcoinSignature_GetPrivateKeyFromSeed(t *testing.T) { + var ( + mockWantedPrivKey256Bits, _ = btcec.PrivKeyFromBytes(DefaultBitcoinCurve(), mockBitcoinPrivKey32Bytes[:]) + mockWantedPrivKey384Bits, _ = btcec.PrivKeyFromBytes(DefaultBitcoinCurve(), mockBitcoinPrivKey48Bytes[:]) + mockWantedPrivKey512Bits, _ = btcec.PrivKeyFromBytes(DefaultBitcoinCurve(), mockBitcoinPrivKey64Bytes[:]) + ) + type fields struct { + NetworkParams *chaincfg.Params + Curve *btcec.KoblitzCurve + } + type args struct { + seed string + privkeyLength model.PrivateKeyBytesLength + } + tests := []struct { + name string + fields fields + args args + want *btcec.PrivateKey + wantErr bool + }{ + + { + name: "wantSuccess:PrivateKey256Bits", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + seed: mockBitcoinSeed, + privkeyLength: model.PrivateKeyBytesLength_PrivateKey256Bits, + }, + want: mockWantedPrivKey256Bits, + wantErr: false, + }, + { + name: "wantSuccess:PrivateKey384Bits", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + seed: mockBitcoinSeed, + privkeyLength: model.PrivateKeyBytesLength_PrivateKey384Bits, + }, + want: mockWantedPrivKey384Bits, + wantErr: false, + }, + { + name: "wantSuccess:PrivateKey512Bits", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + seed: mockBitcoinSeed, + privkeyLength: model.PrivateKeyBytesLength_PrivateKey512Bits, + }, + want: mockWantedPrivKey512Bits, + wantErr: false, + }, + { + name: "wantFail:InvalidPrivateKeyLength", + fields: fields{}, + args: args{ + seed: mockBitcoinSeed, + privkeyLength: model.PrivateKeyBytesLength_PrivateKeyInvalid, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BitcoinSignature{ + NetworkParams: tt.fields.NetworkParams, + Curve: tt.fields.Curve, + } + got, err := b.GetPrivateKeyFromSeed(tt.args.seed, tt.args.privkeyLength) + if (err != nil) != tt.wantErr { + t.Errorf("BitcoinSignature.GetPrivateKeyFromSeed() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("BitcoinSignature.GetPrivateKeyFromSeed() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestBitcoinSignature_GetPublicKeyFromSeed(t *testing.T) { + type fields struct { + NetworkParams *chaincfg.Params + Curve *btcec.KoblitzCurve + } + type args struct { + seed string + format model.BitcoinPublicKeyFormat + privkeyLength model.PrivateKeyBytesLength + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "wantSuccess", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + seed: mockBitcoinSeed, + format: model.BitcoinPublicKeyFormat_PublicKeyFormatCompressed, + privkeyLength: model.PrivateKeyBytesLength_PrivateKey256Bits, + }, + want: mockBitcoinPublicKetBytes, + wantErr: false, + }, + { + name: "wantFail:InvalidPrivateKey", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + seed: mockBitcoinSeed, + format: model.BitcoinPublicKeyFormat_PublicKeyFormatCompressed, + privkeyLength: model.PrivateKeyBytesLength_PrivateKeyInvalid, + }, + want: nil, + wantErr: true, + }, + { + name: "wantFail:InvalidPublicKeyFormat", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + seed: mockBitcoinSeed, + format: model.BitcoinPublicKeyFormat(-1), + privkeyLength: model.PrivateKeyBytesLength_PrivateKey256Bits, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BitcoinSignature{ + NetworkParams: tt.fields.NetworkParams, + Curve: tt.fields.Curve, + } + got, err := b.GetPublicKeyFromSeed(tt.args.seed, tt.args.format, tt.args.privkeyLength) + if (err != nil) != tt.wantErr { + t.Errorf("BitcoinSignature.GetPublicKeyFromSeed() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("BitcoinSignature.GetPublicKeyFromSeed() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestBitcoinSignature_GetPublicKeyFromPrivateKey(t *testing.T) { + var mockPrivateKey, mockPubKey = btcec.PrivKeyFromBytes(DefaultBitcoinCurve(), mockBitcoinPrivKey32Bytes[:]) + type fields struct { + NetworkParams *chaincfg.Params + Curve *btcec.KoblitzCurve + } + type args struct { + privateKey *btcec.PrivateKey + format model.BitcoinPublicKeyFormat + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "wantSuccess:CompressedFormat", + fields: fields{}, + args: args{ + privateKey: mockPrivateKey, + format: model.BitcoinPublicKeyFormat_PublicKeyFormatCompressed, + }, + want: mockPubKey.SerializeCompressed(), + wantErr: false, + }, + { + name: "wantSuccess:UncompressedFormat", + fields: fields{}, + args: args{ + privateKey: mockPrivateKey, + format: model.BitcoinPublicKeyFormat_PublicKeyFormatUncompressed, + }, + want: mockPubKey.SerializeUncompressed(), + wantErr: false, + }, + { + name: "wantFail:InvalidFormat", + fields: fields{}, + args: args{ + privateKey: mockPrivateKey, + format: model.BitcoinPublicKeyFormat(-1), + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BitcoinSignature{ + NetworkParams: tt.fields.NetworkParams, + Curve: tt.fields.Curve, + } + got, err := b.GetPublicKeyFromPrivateKey(tt.args.privateKey, tt.args.format) + if (err != nil) != tt.wantErr { + t.Errorf("BitcoinSignature.GetPublicKeyFromPrivateKey() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("BitcoinSignature.GetPublicKeyFromPrivateKey() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestBitcoinSignature_GetPublicKeyString(t *testing.T) { + type fields struct { + NetworkParams *chaincfg.Params + Curve *btcec.KoblitzCurve + } + type args struct { + publicKey []byte + } + tests := []struct { + name string + fields fields + args args + want string + wantErr bool + }{ + { + name: "wantSuccess", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + publicKey: mockBitcoinPublicKetBytes, + }, + want: "0352f7c0f324cf475a0367dc2f73400f0d3bbae72d2a95490c05a68dcdb19c4d7a", + wantErr: false, + }, + { + name: "wantFailed", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + publicKey: []byte{2, 231, 191, 45, 151, 205, 3, 121, 159, 114, 31, 223, 160, 57}, + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BitcoinSignature{ + NetworkParams: tt.fields.NetworkParams, + Curve: tt.fields.Curve, + } + got, err := b.GetPublicKeyString(tt.args.publicKey) + if (err != nil) != tt.wantErr { + t.Errorf("BitcoinSignature.GetPublicKeyString() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("BitcoinSignature.GetPublicKeyString() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestBitcoinSignature_GetAddressFromPublicKey(t *testing.T) { + type fields struct { + NetworkParams *chaincfg.Params + Curve *btcec.KoblitzCurve + } + type args struct { + publicKey []byte + } + tests := []struct { + name string + fields fields + args args + want string + wantErr bool + }{ + { + name: "wantSuccess", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + publicKey: mockBitcoinPublicKetBytes, + }, + want: "12Ea6WAMZhFnfM5kjyfrfykqVWFcaWorQ8", + wantErr: false, + }, + { + name: "wnatFailed", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + publicKey: []byte{}, + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BitcoinSignature{ + NetworkParams: tt.fields.NetworkParams, + Curve: tt.fields.Curve, + } + got, err := b.GetAddressFromPublicKey(tt.args.publicKey) + if (err != nil) != tt.wantErr { + t.Errorf("BitcoinSignature.GetAddressFromPublicKey() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("BitcoinSignature.GetAddressFromPublicKey() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestBitcoinSignature_GetAddressBytes(t *testing.T) { + type fields struct { + NetworkParams *chaincfg.Params + Curve *btcec.KoblitzCurve + } + type args struct { + address string + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "wantSuccess", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + address: "12Ea6WAMZhFnfM5kjyfrfykqVWFcaWorQ8", + }, + want: []byte{13, 137, 40, 212, 218, 119, 144, 80, 70, 113, 150, 129, 2, 84, 45, 144, 145, 17, 64, 134}, + wantErr: false, + }, + { + name: "wantFailed", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + address: "", + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BitcoinSignature{ + NetworkParams: tt.fields.NetworkParams, + Curve: tt.fields.Curve, + } + got, err := b.GetAddressBytes(tt.args.address) + if (err != nil) != tt.wantErr { + t.Errorf("BitcoinSignature.GetAddressBytes() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("BitcoinSignature.GetAddressBytes() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestBitcoinSignature_GetSignatureFromBytes(t *testing.T) { + var ( + mockPrivateKey, _ = btcec.PrivKeyFromBytes(DefaultBitcoinCurve(), mockBitcoinPrivKey32Bytes[:]) + mockSignature, _ = mockPrivateKey.Sign([]byte{12, 1, 2, 1}) + ) + type fields struct { + NetworkParams *chaincfg.Params + Curve *btcec.KoblitzCurve + } + type args struct { + signatureBytes []byte + } + tests := []struct { + name string + fields fields + args args + want *btcec.Signature + wantErr bool + }{ + { + name: "wantSuccess", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + signatureBytes: mockSignature.Serialize(), + }, + want: mockSignature, + wantErr: false, + }, + { + name: "wantFailed", + fields: fields{ + NetworkParams: DefaultBitcoinNetworkParams(), + Curve: DefaultBitcoinCurve(), + }, + args: args{ + signatureBytes: []byte{2, 1, 2}, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BitcoinSignature{ + NetworkParams: tt.fields.NetworkParams, + Curve: tt.fields.Curve, + } + got, err := b.GetSignatureFromBytes(tt.args.signatureBytes) + if (err != nil) != tt.wantErr { + t.Errorf("BitcoinSignature.GetSignatureFromBytes() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("BitcoinSignature.GetSignatureFromBytes() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/common/crypto/ed25519.go b/common/crypto/ed25519.go index ee4e28f23..5df2869dd 100644 --- a/common/crypto/ed25519.go +++ b/common/crypto/ed25519.go @@ -53,7 +53,7 @@ func (es *Ed25519Signature) GetAddressFromSeed(seed string) string { } // GetPublicKeyFromPrivateKey get public key bytes from private key -func (es *Ed25519Signature) GetPublicKeyFromPrivateKey(privateKey []byte) ([]byte, error) { +func (*Ed25519Signature) GetPublicKeyFromPrivateKey(privateKey []byte) ([]byte, error) { if len(privateKey) != ed25519.PrivateKeySize { return nil, blocker.NewBlocker(blocker.ValidationErr, "invalid ed25519 private key") } diff --git a/common/crypto/ed25519_test.go b/common/crypto/ed25519_test.go index 21107f330..9b58f5c10 100644 --- a/common/crypto/ed25519_test.go +++ b/common/crypto/ed25519_test.go @@ -185,3 +185,79 @@ func TestEd25519Signature_GetPublicKeyFromAddress(t *testing.T) { }) } } + +func TestEd25519Signature_GetPublicKeyFromPrivateKey(t *testing.T) { + var mockPrivateKey = []byte{188, 149, 6, 52, 103, 250, 141, 133, 84, 93, 225, 77, 118, 252, 111, 71, 115, 7, 109, 188, 229, 212, + 31, 2, 189, 96, 77, 11, 89, 44, 125, 12, 183, 227, 106, 207, 27, 80, 168, 160, 252, 110, 172, 177, 36, 171, + 249, 50, 21, 23, 18, 168, 96, 125, 32, 72, 124, 33, 96, 51, 231, 163, 156, 224} + type args struct { + privateKey []byte + } + tests := []struct { + name string + e *Ed25519Signature + args args + want []byte + wantErr bool + }{ + { + name: "wantSuccess", + args: args{ + privateKey: mockPrivateKey, + }, + want: mockPrivateKey[32:], + wantErr: false, + }, + { + name: "wantFailed", + args: args{ + privateKey: []byte{}, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := &Ed25519Signature{} + got, err := e.GetPublicKeyFromPrivateKey(tt.args.privateKey) + if (err != nil) != tt.wantErr { + t.Errorf("Ed25519Signature.GetPublicKeyFromPrivateKey() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Ed25519Signature.GetPublicKeyFromPrivateKey() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestEd25519Signature_GetPrivateKeyFromSeed(t *testing.T) { + type args struct { + seed string + } + tests := []struct { + name string + e *Ed25519Signature + args args + want []byte + }{ + { + name: "wantSuccess", + args: args{ + seed: ed25519MockAddress, + }, + want: []byte{188, 149, 6, 52, 103, 250, 141, 133, 84, 93, 225, 77, 118, 252, 111, 71, 115, 7, 109, 188, 229, 212, + 31, 2, 189, 96, 77, 11, 89, 44, 125, 12, 183, 227, 106, 207, 27, 80, 168, 160, 252, 110, 172, 177, 36, 171, + 249, 50, 21, 23, 18, 168, 96, 125, 32, 72, 124, 33, 96, 51, 231, 163, 156, 224}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := &Ed25519Signature{} + if got := e.GetPrivateKeyFromSeed(tt.args.seed); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Ed25519Signature.GetPrivateKeyFromSeed() = %v, want %v", got, tt.want) + } + }) + } +} From 262bace47acbe80928db0ce5e85ea38eaae32e79 Mon Sep 17 00:00:00 2001 From: Gede Sukra Widhyawan Date: Thu, 19 Mar 2020 08:34:25 +0800 Subject: [PATCH 3/3] add unit test --- common/crypto/bitcoinSignature.go | 10 +++++----- common/crypto/ed25519.go | 8 ++++---- common/crypto/ed25519_test.go | 4 ++-- common/crypto/signature.go | 21 ++++++++------------- common/crypto/signature_test.go | 21 +++++++++++++++++++-- 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/common/crypto/bitcoinSignature.go b/common/crypto/bitcoinSignature.go index 514414502..2c86df97f 100644 --- a/common/crypto/bitcoinSignature.go +++ b/common/crypto/bitcoinSignature.go @@ -56,7 +56,7 @@ func NewBitcoinSignature(netParams *chaincfg.Params, curve *btcec.KoblitzCurve) func (*BitcoinSignature) Sign(privateKey *btcec.PrivateKey, payload []byte) ([]byte, error) { var sig, err = privateKey.Sign(payload) if err != nil { - return nil, err + return nil, blocker.NewBlocker(blocker.AuthErr, err.Error()) } return sig.Serialize(), nil } @@ -143,7 +143,7 @@ func (b *BitcoinSignature) GetPublicKeyFromBytes(pubkey []byte) (*btcec.PublicKe func (b *BitcoinSignature) GetPublicKeyString(publicKey []byte) (string, error) { var address, err = btcutil.NewAddressPubKey(publicKey, b.GetNetworkParams()) if err != nil { - return "", err + return "", blocker.NewBlocker(blocker.ParserErr, err.Error()) } return address.String(), nil } @@ -152,7 +152,7 @@ func (b *BitcoinSignature) GetPublicKeyString(publicKey []byte) (string, error) func (b *BitcoinSignature) GetAddressFromPublicKey(publicKey []byte) (string, error) { var address, err = btcutil.NewAddressPubKey(publicKey, b.GetNetworkParams()) if err != nil { - return "", err + return "", blocker.NewBlocker(blocker.ParserErr, err.Error()) } return address.EncodeAddress(), nil } @@ -161,7 +161,7 @@ func (b *BitcoinSignature) GetAddressFromPublicKey(publicKey []byte) (string, er func (b *BitcoinSignature) GetAddressBytes(address string) ([]byte, error) { var decodedAddress, err = btcutil.DecodeAddress(address, b.GetNetworkParams()) if err != nil { - return nil, err + return nil, blocker.NewBlocker(blocker.ParserErr, err.Error()) } return decodedAddress.ScriptAddress(), nil } @@ -170,7 +170,7 @@ func (b *BitcoinSignature) GetAddressBytes(address string) ([]byte, error) { func (b *BitcoinSignature) GetSignatureFromBytes(signatureBytes []byte) (*btcec.Signature, error) { var signature, err = btcec.ParseSignature(signatureBytes, b.Curve) if err != nil { - return nil, err + return nil, blocker.NewBlocker(blocker.ParserErr, err.Error()) } return signature, nil } diff --git a/common/crypto/ed25519.go b/common/crypto/ed25519.go index 5df2869dd..47f74dfbe 100644 --- a/common/crypto/ed25519.go +++ b/common/crypto/ed25519.go @@ -2,7 +2,6 @@ package crypto import ( "encoding/base64" - "fmt" "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/util" @@ -55,7 +54,7 @@ func (es *Ed25519Signature) GetAddressFromSeed(seed string) string { // GetPublicKeyFromPrivateKey get public key bytes from private key func (*Ed25519Signature) GetPublicKeyFromPrivateKey(privateKey []byte) ([]byte, error) { if len(privateKey) != ed25519.PrivateKeySize { - return nil, blocker.NewBlocker(blocker.ValidationErr, "invalid ed25519 private key") + return nil, blocker.NewBlocker(blocker.AppErr, "invalid ed25519 private key") } return privateKey[32:], nil } @@ -70,11 +69,12 @@ func (*Ed25519Signature) GetPublicKeyFromAddress(address string) ([]byte, error) // decode base64 back to byte publicKey, err := base64.URLEncoding.DecodeString(address) if err != nil { - return nil, err + + return nil, blocker.NewBlocker(blocker.AppErr, err.Error()) } // Needs to check the checksum bit at the end, and if valid, if publicKey[32] != util.GetChecksumByte(publicKey[:32]) { - return nil, fmt.Errorf("address checksum failed") + return nil, blocker.NewBlocker(blocker.AppErr, "address checksum failed") } return publicKey[:32], nil } diff --git a/common/crypto/ed25519_test.go b/common/crypto/ed25519_test.go index 9b58f5c10..dd9ebd23b 100644 --- a/common/crypto/ed25519_test.go +++ b/common/crypto/ed25519_test.go @@ -155,7 +155,7 @@ func TestEd25519Signature_GetPublicKeyFromAddress(t *testing.T) { wantErr: false, }, { - name: "wantFail-{decode error, wrong address format/length}", + name: "wantFail-{decode-error-wrong-address-format/length}", args: args{ address: "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgt", }, @@ -163,7 +163,7 @@ func TestEd25519Signature_GetPublicKeyFromAddress(t *testing.T) { wantErr: true, }, { - name: "wantFail:fail-{checksum error, wrong address format}", + name: "wantFail:fail-{checksum-error-wrong-address-format}", args: args{ address: "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtM", }, diff --git a/common/crypto/signature.go b/common/crypto/signature.go index 9fa424f86..588a932e0 100644 --- a/common/crypto/signature.go +++ b/common/crypto/signature.go @@ -106,10 +106,7 @@ func (*Signature) VerifySignature(payload, signature []byte, accountAddress stri accountPublicKey, err = ed25519Signature.GetPublicKeyFromAddress(accountAddress) ) if err != nil { - return blocker.NewBlocker( - blocker.ValidationErr, - err.Error(), - ) + return err } if !ed25519Signature.Verify(accountPublicKey, payload, signature[4:]) { return blocker.NewBlocker( @@ -136,10 +133,7 @@ func (*Signature) VerifySignature(payload, signature []byte, accountAddress stri } signaturePubKeyAddress, err := bitcoinSignature.GetAddressFromPublicKey(signaturePubKeyBytes) if err != nil { - return blocker.NewBlocker( - blocker.ValidationErr, - err.Error(), - ) + return err } // check sender account address to address from public key in signature if accountAddress != signaturePubKeyAddress { @@ -150,10 +144,8 @@ func (*Signature) VerifySignature(payload, signature []byte, accountAddress stri } sig, err := bitcoinSignature.GetSignatureFromBytes(signature[signatureFirstBytesIndex:]) if err != nil { - return blocker.NewBlocker( - blocker.ValidationErr, - err.Error(), - ) + return err + } if !bitcoinSignature.Verify(payload, sig, signaturePubKey) { return blocker.NewBlocker( @@ -187,7 +179,10 @@ func (*Signature) GenerateAccountFromSeed(signatureType model.SignatureType, see case model.SignatureType_DefaultSignature: var ed25519Signature = NewEd25519Signature() privateKey = ed25519Signature.GetPrivateKeyFromSeed(seed) - publicKey = ed25519Signature.GetPublicKeyFromSeed(seed) + publicKey, err = ed25519Signature.GetPublicKeyFromPrivateKey(privateKey) + if err != nil { + return nil, nil, "", "", err + } publickKeyString = ed25519Signature.GetPublicKeyString(publicKey) address, err = ed25519Signature.GetAddressFromPublicKey(publicKey) if err != nil { diff --git a/common/crypto/signature_test.go b/common/crypto/signature_test.go index 8a8d3781c..152aec077 100644 --- a/common/crypto/signature_test.go +++ b/common/crypto/signature_test.go @@ -1,6 +1,7 @@ package crypto import ( + "encoding/base64" "reflect" "testing" @@ -134,7 +135,7 @@ func TestSignature_VerifySignature(t *testing.T) { want error }{ { - name: "VerifySignature:success-{default-signature}", + name: "VerifySignature:success-{ed25519-signature}", args: args{ payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54}, accountAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE", @@ -171,12 +172,28 @@ func TestSignature_VerifySignature(t *testing.T) { "InvalidSignatureType", ), }, + { + name: "VerifySignature:failed-{ed25519-invalid-PublicKey}", + args: args{ + payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54}, + accountAddress: "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgt", + signature: []byte{0, 0, 0, 0, 33, 0, 3, 82, 247, 192, 243, 36, 207, 71, 90, 3, 103, 220, 47, 115, 64, 15, 13, 59, 186, 231, 45, + 42, 149, 73, 12, 5, 166, 141, 205, 177, 156, 77, 122, 48, 68, 2, 32, 90, 19, 249, 248, 141, 2, 142, 176, 69, 131, 63, 122, + 227, 255, 114, 26, 116, 34, 23, 167, 245, 190, 121, 156, 49, 171, 110, 198, 76, 191, 126, 236, 2, 32, 9, 133, 158, 144, + 106, 172, 10, 8, 201, 172, 22, 1, 23, 102, 80, 158, 55, 191, 144, 127, 111, 186, 226, 211, 3, 203, 131, 93, 140, 126, 90, + 133}, + }, + want: blocker.NewBlocker( + blocker.AppErr, + base64.CorruptInputError(40).Error(), + ), + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := &Signature{} if got := s.VerifySignature(tt.args.payload, tt.args.signature, tt.args.accountAddress); got != tt.want { - t.Errorf("Signature.VerifySignature() = %v, want %v", got, tt.want) + t.Errorf("Signature.VerifySignature() = \n%v, want \n%v", got, tt.want) } }) }