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 }