git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/crypto/ecdsa/public.go (about)

     1  package frostfsecdsa
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/sha256"
     7  	"crypto/sha512"
     8  	"fmt"
     9  	"math/big"
    10  
    11  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    12  )
    13  
    14  // PublicKey is a wrapper over ecdsa.PublicKey used for FrostFS needs.
    15  // Provides frostfscrypto.PublicKey interface.
    16  //
    17  // Instances MUST be initialized from ecdsa.PublicKey using type conversion.
    18  type PublicKey ecdsa.PublicKey
    19  
    20  // MaxEncodedSize returns size of the compressed ECDSA public key.
    21  func (x PublicKey) MaxEncodedSize() int {
    22  	return 33
    23  }
    24  
    25  // Encode encodes ECDSA public key in compressed form into buf.
    26  // Uses exactly MaxEncodedSize bytes of the buf.
    27  //
    28  // Encode panics if buf length is less than MaxEncodedSize.
    29  //
    30  // See also Decode.
    31  func (x PublicKey) Encode(buf []byte) int {
    32  	if len(buf) < 33 {
    33  		panic(fmt.Sprintf("too short buffer %d", len(buf)))
    34  	}
    35  
    36  	return copy(buf, (*keys.PublicKey)(&x).Bytes())
    37  }
    38  
    39  // Decode decodes compressed binary representation of the PublicKey.
    40  //
    41  // See also Encode.
    42  func (x *PublicKey) Decode(data []byte) error {
    43  	pub, err := keys.NewPublicKeyFromBytes(data, elliptic.P256())
    44  	if err != nil {
    45  		return err
    46  	}
    47  
    48  	*x = (PublicKey)(*pub)
    49  
    50  	return nil
    51  }
    52  
    53  // similar to elliptic.Unmarshal but without IsOnCurve check.
    54  func unmarshalXY(data []byte) (x *big.Int, y *big.Int) {
    55  	if len(data) != 65 {
    56  		return
    57  	} else if data[0] != 4 { // uncompressed form
    58  		return
    59  	}
    60  
    61  	p := elliptic.P256().Params().P
    62  	x = new(big.Int).SetBytes(data[1:33])
    63  	y = new(big.Int).SetBytes(data[33:])
    64  
    65  	if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 {
    66  		x, y = nil, nil
    67  	}
    68  
    69  	return
    70  }
    71  
    72  // Verify verifies data signature calculated by ECDSA algorithm with SHA-512 hashing.
    73  func (x PublicKey) Verify(data, signature []byte) bool {
    74  	h := sha512.Sum512(data)
    75  	r, s := unmarshalXY(signature)
    76  
    77  	return r != nil && s != nil && ecdsa.Verify((*ecdsa.PublicKey)(&x), h[:], r, s)
    78  }
    79  
    80  // PublicKeyRFC6979 is a wrapper over ecdsa.PublicKey used for FrostFS needs.
    81  // Provides frostfscrypto.PublicKey interface.
    82  //
    83  // Instances MUST be initialized from ecdsa.PublicKey using type conversion.
    84  type PublicKeyRFC6979 ecdsa.PublicKey
    85  
    86  // MaxEncodedSize returns size of the compressed ECDSA public key.
    87  func (x PublicKeyRFC6979) MaxEncodedSize() int {
    88  	return 33
    89  }
    90  
    91  // Encode encodes ECDSA public key in compressed form into buf.
    92  // Uses exactly MaxEncodedSize bytes of the buf.
    93  //
    94  // Encode panics if buf length is less than MaxEncodedSize.
    95  //
    96  // See also Decode.
    97  func (x PublicKeyRFC6979) Encode(buf []byte) int {
    98  	if len(buf) < 33 {
    99  		panic(fmt.Sprintf("too short buffer %d", len(buf)))
   100  	}
   101  
   102  	return copy(buf, (*keys.PublicKey)(&x).Bytes())
   103  }
   104  
   105  // Decode decodes binary representation of the ECDSA public key.
   106  //
   107  // See also Encode.
   108  func (x *PublicKeyRFC6979) Decode(data []byte) error {
   109  	pub, err := keys.NewPublicKeyFromBytes(data, elliptic.P256())
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	*x = (PublicKeyRFC6979)(*pub)
   115  
   116  	return nil
   117  }
   118  
   119  // Verify verifies data signature calculated by deterministic ECDSA algorithm
   120  // with SHA-256 hashing.
   121  //
   122  // See also RFC 6979.
   123  func (x PublicKeyRFC6979) Verify(data, signature []byte) bool {
   124  	h := sha256.Sum256(data)
   125  	return (*keys.PublicKey)(&x).Verify(signature, h[:])
   126  }