github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/ecdsa_public_key.go (about)

     1  package hedera
     2  
     3  /*-
     4   *
     5   * Hedera Go SDK
     6   *
     7   * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
     8   *
     9   * Licensed under the Apache License, Version 2.0 (the "License");
    10   * you may not use this file except in compliance with the License.
    11   * You may obtain a copy of the License at
    12   *
    13   *      http://www.apache.org/licenses/LICENSE-2.0
    14   *
    15   * Unless required by applicable law or agreed to in writing, software
    16   * distributed under the License is distributed on an "AS IS" BASIS,
    17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    18   * See the License for the specific language governing permissions and
    19   * limitations under the License.
    20   *
    21   */
    22  
    23  import (
    24  	"bytes"
    25  	"crypto/ecdsa"
    26  	"crypto/elliptic"
    27  	"encoding/asn1"
    28  	"encoding/hex"
    29  	"math/big"
    30  	"strings"
    31  
    32  	"github.com/btcsuite/btcd/btcec/v2"
    33  	"github.com/ethereum/go-ethereum/crypto"
    34  	"github.com/hashgraph/hedera-protobufs-go/services"
    35  	"github.com/pkg/errors"
    36  )
    37  
    38  type _ECDSAPublicKey struct {
    39  	*ecdsa.PublicKey
    40  }
    41  
    42  const _LegacyECDSAPubKeyPrefix = "302d300706052b8104000a032200"
    43  
    44  func _ECDSAPublicKeyFromBytes(byt []byte) (*_ECDSAPublicKey, error) {
    45  	length := len(byt)
    46  	switch length {
    47  	case 33:
    48  		return _ECDSAPublicKeyFromBytesRaw(byt)
    49  	case 47:
    50  		return _LegacyECDSAPublicKeyFromBytesDer(byt)
    51  	case 56:
    52  		return _ECDSAPublicKeyFromBytesDer(byt)
    53  	default:
    54  		return &_ECDSAPublicKey{}, _NewErrBadKeyf("invalid compressed ECDSA public key length: %v bytes", len(byt))
    55  	}
    56  }
    57  
    58  func _ECDSAPublicKeyFromBytesRaw(byt []byte) (*_ECDSAPublicKey, error) {
    59  	if byt == nil {
    60  		return &_ECDSAPublicKey{}, errByteArrayNull
    61  	}
    62  	if len(byt) != 33 {
    63  		return &_ECDSAPublicKey{}, _NewErrBadKeyf("invalid public key length: %v bytes", len(byt))
    64  	}
    65  
    66  	key, err := crypto.DecompressPubkey(byt)
    67  	if err != nil {
    68  		return &_ECDSAPublicKey{}, err
    69  	}
    70  
    71  	return &_ECDSAPublicKey{
    72  		key,
    73  	}, nil
    74  }
    75  
    76  func _LegacyECDSAPublicKeyFromBytesDer(byt []byte) (*_ECDSAPublicKey, error) {
    77  	if byt == nil {
    78  		return &_ECDSAPublicKey{}, errByteArrayNull
    79  	}
    80  
    81  	given := hex.EncodeToString(byt)
    82  	result := strings.ReplaceAll(given, _LegacyECDSAPubKeyPrefix, "")
    83  	decoded, err := hex.DecodeString(result)
    84  	if err != nil {
    85  		return &_ECDSAPublicKey{}, err
    86  	}
    87  
    88  	if len(decoded) != 33 {
    89  		return &_ECDSAPublicKey{}, _NewErrBadKeyf("invalid public key length: %v bytes", len(byt))
    90  	}
    91  
    92  	key, err := crypto.DecompressPubkey(decoded)
    93  	if err != nil {
    94  		return &_ECDSAPublicKey{}, err
    95  	}
    96  
    97  	return &_ECDSAPublicKey{
    98  		key,
    99  	}, nil
   100  }
   101  func _ECDSAPublicKeyFromBytesDer(byt []byte) (*_ECDSAPublicKey, error) {
   102  	if byt == nil {
   103  		return &_ECDSAPublicKey{}, errByteArrayNull
   104  	}
   105  
   106  	type AlgorithmIdentifier struct {
   107  		Algorithm  asn1.ObjectIdentifier
   108  		Parameters asn1.ObjectIdentifier
   109  	}
   110  
   111  	type PublicKeyInfo struct {
   112  		AlgorithmIdentifier AlgorithmIdentifier
   113  		PublicKey           asn1.BitString
   114  	}
   115  
   116  	key := &PublicKeyInfo{}
   117  	_, err := asn1.Unmarshal(byt, key)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	// Check if the parsed key uses ECDSA public key algorithm
   123  	ecdsaPublicKeyAlgorithmOID := asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
   124  	if !key.AlgorithmIdentifier.Algorithm.Equal(ecdsaPublicKeyAlgorithmOID) {
   125  		return nil, errors.New("public key is not an ECDSA public key")
   126  	}
   127  
   128  	// Check if the parsed key uses secp256k1 curve
   129  	secp256k1OID := asn1.ObjectIdentifier{1, 3, 132, 0, 10}
   130  	if !key.AlgorithmIdentifier.Parameters.Equal(secp256k1OID) {
   131  		return nil, errors.New("public key is not a secp256k1 public key")
   132  	}
   133  
   134  	// Check if the public key is compressed and decompress it if necessary
   135  	var pubKeyBytes []byte
   136  	if key.PublicKey.Bytes[0] == 0x02 || key.PublicKey.Bytes[0] == 0x03 {
   137  		// Decompress the public key
   138  		pubKey, err := btcec.ParsePubKey(key.PublicKey.Bytes)
   139  		if err != nil {
   140  			return nil, err
   141  		}
   142  		pubKeyBytes = pubKey.SerializeUncompressed()
   143  	} else {
   144  		pubKeyBytes = key.PublicKey.Bytes
   145  	}
   146  
   147  	if len(pubKeyBytes) != 65 {
   148  		return nil, errors.New("invalid public key length")
   149  	}
   150  
   151  	x := new(big.Int).SetBytes(pubKeyBytes[1:33])
   152  	y := new(big.Int).SetBytes(pubKeyBytes[33:])
   153  
   154  	pubKey := &ecdsa.PublicKey{
   155  		Curve: btcec.S256(),
   156  		X:     x,
   157  		Y:     y,
   158  	}
   159  
   160  	// Validate the public key
   161  	if !pubKey.Curve.IsOnCurve(pubKey.X, pubKey.Y) {
   162  		return nil, errors.New("public key is not on the curve")
   163  	}
   164  
   165  	return &_ECDSAPublicKey{
   166  		PublicKey: pubKey,
   167  	}, nil
   168  }
   169  
   170  func _ECDSAPublicKeyFromString(s string) (*_ECDSAPublicKey, error) {
   171  	byt, err := hex.DecodeString(s)
   172  	if err != nil {
   173  		return &_ECDSAPublicKey{}, err
   174  	}
   175  
   176  	return _ECDSAPublicKeyFromBytes(byt)
   177  }
   178  
   179  func (pk _ECDSAPublicKey) _BytesRaw() []byte {
   180  	return crypto.CompressPubkey(pk.PublicKey)
   181  }
   182  
   183  func (pk _ECDSAPublicKey) _BytesDer() []byte {
   184  	// Marshal the public key
   185  	publicKeyBytes := pk._BytesRaw()
   186  
   187  	// Define the public key structure
   188  	publicKeyInfo := struct {
   189  		Algorithm struct {
   190  			Algorithm  asn1.ObjectIdentifier
   191  			Parameters asn1.ObjectIdentifier
   192  		}
   193  		PublicKey asn1.BitString
   194  	}{
   195  		Algorithm: struct {
   196  			Algorithm  asn1.ObjectIdentifier
   197  			Parameters asn1.ObjectIdentifier
   198  		}{
   199  			Algorithm:  asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}, // id-ecPublicKey
   200  			Parameters: asn1.ObjectIdentifier{1, 3, 132, 0, 10},       // secp256k1
   201  		},
   202  		PublicKey: asn1.BitString{
   203  			Bytes:     publicKeyBytes,
   204  			BitLength: 8 * len(publicKeyBytes),
   205  		},
   206  	}
   207  
   208  	// Marshal the public key info into DER format
   209  	derBytes, err := asn1.Marshal(publicKeyInfo)
   210  	if err != nil {
   211  		return nil
   212  	}
   213  
   214  	return derBytes
   215  }
   216  
   217  func (pk _ECDSAPublicKey) String() string {
   218  	return pk._StringRaw()
   219  }
   220  func (pk _ECDSAPublicKey) _StringRaw() string {
   221  	return hex.EncodeToString(pk._BytesRaw())
   222  }
   223  func (pk _ECDSAPublicKey) _StringDer() string {
   224  	return hex.EncodeToString(pk._BytesDer())
   225  }
   226  
   227  func (pk _ECDSAPublicKey) _ToProtoKey() *services.Key {
   228  	b := crypto.CompressPubkey(pk.PublicKey)
   229  	return &services.Key{Key: &services.Key_ECDSASecp256K1{ECDSASecp256K1: b}}
   230  }
   231  
   232  func (pk _ECDSAPublicKey) _ToSignaturePairProtobuf(signature []byte) *services.SignaturePair {
   233  	return &services.SignaturePair{
   234  		PubKeyPrefix: pk._BytesRaw(),
   235  		Signature: &services.SignaturePair_ECDSASecp256K1{
   236  			ECDSASecp256K1: signature,
   237  		},
   238  	}
   239  }
   240  
   241  func (pk _ECDSAPublicKey) _Verify(message []byte, signature []byte) bool {
   242  	return crypto.VerifySignature(pk._BytesRaw(), message, signature)
   243  }
   244  
   245  func (pk _ECDSAPublicKey) _VerifyTransaction(tx Transaction) bool {
   246  	if tx.signedTransactions._Length() == 0 {
   247  		return false
   248  	}
   249  
   250  	_, _ = tx._BuildAllTransactions()
   251  
   252  	for _, value := range tx.signedTransactions.slice {
   253  		tx := value.(*services.SignedTransaction)
   254  		found := false
   255  		for _, sigPair := range tx.SigMap.GetSigPair() {
   256  			if bytes.Equal(sigPair.GetPubKeyPrefix(), pk._BytesRaw()) {
   257  				found = true
   258  				if !pk._Verify(tx.BodyBytes, sigPair.GetECDSASecp256K1()) {
   259  					return false
   260  				}
   261  			}
   262  		}
   263  
   264  		if !found {
   265  			return false
   266  		}
   267  	}
   268  
   269  	return true
   270  }
   271  
   272  func (pk _ECDSAPublicKey) _ToFullKey() []byte {
   273  	return elliptic.Marshal(crypto.S256(), pk.X, pk.Y)
   274  }
   275  
   276  func (pk _ECDSAPublicKey) _ToEthereumAddress() string {
   277  	temp := pk._ToFullKey()[1:]
   278  	hash := crypto.Keccak256(temp)
   279  	return hex.EncodeToString(hash[12:])
   280  }