package neofsecdsa import ( "crypto/ecdsa" "crypto/elliptic" "crypto/sha256" "crypto/sha512" "fmt" "math/big" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) // PublicKey implements neofscrypto.PublicKey based on ECDSA. // // Supported schemes: // - neofscrypto.ECDSA_SHA512 (default) // - neofscrypto.ECDSA_DETERMINISTIC_SHA256 type PublicKey struct { deterministic bool key ecdsa.PublicKey } // SetKey specifies ecdsa.PublicKey to be used for ECDSA signature verification. func (x *PublicKey) SetKey(key ecdsa.PublicKey) { x.key = key } // MakeDeterministic makes PublicKey to use Deterministic ECDSA scheme // (see neofscrypto.ECDSA_DETERMINISTIC_SHA256). By default, // neofscrypto.ECDSA_SHA512 is used. func (x *PublicKey) MakeDeterministic() { x.deterministic = true } // MaxEncodedSize returns size of the compressed ECDSA public key. func (x PublicKey) MaxEncodedSize() int { return 33 } // Encode encodes ECDSA public key in compressed form into buf. // Uses exactly MaxEncodedSize bytes of the buf. // // Encode panics if buf length is less than MaxEncodedSize. // // See also Decode. func (x PublicKey) Encode(buf []byte) int { if len(buf) < 33 { panic(fmt.Sprintf("too short buffer %d", len(buf))) } return copy(buf, (*keys.PublicKey)(&x.key).Bytes()) } // Decode decodes compressed binary representation of the PublicKey. // // See also Encode. func (x *PublicKey) Decode(data []byte) error { pub, err := keys.NewPublicKeyFromBytes(data, elliptic.P256()) if err != nil { return err } x.key = (ecdsa.PublicKey)(*pub) return nil } // similar to elliptic.Unmarshal but without IsOnCurve check. func unmarshalXY(data []byte) (x *big.Int, y *big.Int) { if len(data) != 65 { return } else if data[0] != 4 { // uncompressed form return } p := elliptic.P256().Params().P x = new(big.Int).SetBytes(data[1:33]) y = new(big.Int).SetBytes(data[33:]) if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 { x, y = nil, nil } return } // Verify verifies data signature calculated by algorithm depending on // PublicKey state: // - Deterministic ECDSA with SHA-256 hashing if MakeDeterministic called // - ECDSA with SHA-512 hashing, otherwise func (x PublicKey) Verify(data, signature []byte) bool { if x.deterministic { h := sha256.Sum256(data) return (*keys.PublicKey)(&x.key).Verify(signature, h[:]) } h := sha512.Sum512(data) r, s := unmarshalXY(signature) return r != nil && s != nil && ecdsa.Verify(&x.key, h[:], r, s) }