frostfs-sdk-go/crypto/ecdsa/public.go
Leonard Lyubich ea043f4ca3 [#190] Refactor cryptographic functionality
Remove `signature` and `util/signature` packages. Re-implement their
functionality in new `crypto` package. Generalize the approach of
digital signature computation and verification by adding `Signer` and
`PublicKey` primitives similar to standard `crypto` package. Support
already exising in protocol signature schemes.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
2022-04-19 12:55:11 +03:00

78 lines
1.8 KiB
Go

package neofsecdsa
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/sha256"
"crypto/sha512"
"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
}
// 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
}
// Decode decodes compressed binary representation of the PublicKey.
//
// See also Signer.EncodePublicKey.
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)
}