main
Raw Download raw file
  1// Package ed448 implements the ed448 signature algorithm for OpenPGP
  2// as defined in the Open PGP crypto refresh.
  3package ed448
  4
  5import (
  6	"crypto/subtle"
  7	"io"
  8
  9	"github.com/ProtonMail/go-crypto/openpgp/errors"
 10	ed448lib "github.com/cloudflare/circl/sign/ed448"
 11)
 12
 13const (
 14	// PublicKeySize is the size, in bytes, of public keys in this package.
 15	PublicKeySize = ed448lib.PublicKeySize
 16	// SeedSize is the size, in bytes, of private key seeds.
 17	// The private key representation used by RFC 8032.
 18	SeedSize = ed448lib.SeedSize
 19	// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
 20	SignatureSize = ed448lib.SignatureSize
 21)
 22
 23type PublicKey struct {
 24	// Point represents the elliptic curve point of the public key.
 25	Point []byte
 26}
 27
 28type PrivateKey struct {
 29	PublicKey
 30	// Key the private key representation by RFC 8032,
 31	// encoded as seed | public key point.
 32	Key []byte
 33}
 34
 35// NewPublicKey creates a new empty ed448 public key.
 36func NewPublicKey() *PublicKey {
 37	return &PublicKey{}
 38}
 39
 40// NewPrivateKey creates a new empty private key referencing the public key.
 41func NewPrivateKey(key PublicKey) *PrivateKey {
 42	return &PrivateKey{
 43		PublicKey: key,
 44	}
 45}
 46
 47// Seed returns the ed448 private key secret seed.
 48// The private key representation by RFC 8032.
 49func (pk *PrivateKey) Seed() []byte {
 50	return pk.Key[:SeedSize]
 51}
 52
 53// MarshalByteSecret returns the underlying seed of the private key.
 54func (pk *PrivateKey) MarshalByteSecret() []byte {
 55	return pk.Seed()
 56}
 57
 58// UnmarshalByteSecret computes the private key from the secret seed
 59// and stores it in the private key object.
 60func (sk *PrivateKey) UnmarshalByteSecret(seed []byte) error {
 61	sk.Key = ed448lib.NewKeyFromSeed(seed)
 62	return nil
 63}
 64
 65// GenerateKey generates a fresh private key with the provided randomness source.
 66func GenerateKey(rand io.Reader) (*PrivateKey, error) {
 67	publicKey, privateKey, err := ed448lib.GenerateKey(rand)
 68	if err != nil {
 69		return nil, err
 70	}
 71	privateKeyOut := new(PrivateKey)
 72	privateKeyOut.PublicKey.Point = publicKey[:]
 73	privateKeyOut.Key = privateKey[:]
 74	return privateKeyOut, nil
 75}
 76
 77// Sign signs a message with the ed448 algorithm.
 78// priv MUST be a valid key! Check this with Validate() before use.
 79func Sign(priv *PrivateKey, message []byte) ([]byte, error) {
 80	// Ed448 is used with the empty string as a context string.
 81	// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-08#section-13.7
 82	return ed448lib.Sign(priv.Key, message, ""), nil
 83}
 84
 85// Verify verifies a ed448 signature
 86func Verify(pub *PublicKey, message []byte, signature []byte) bool {
 87	// Ed448 is used with the empty string as a context string.
 88	// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-08#section-13.7
 89	return ed448lib.Verify(pub.Point, message, signature, "")
 90}
 91
 92// Validate checks if the ed448 private key is valid
 93func Validate(priv *PrivateKey) error {
 94	expectedPrivateKey := ed448lib.NewKeyFromSeed(priv.Seed())
 95	if subtle.ConstantTimeCompare(priv.Key, expectedPrivateKey) == 0 {
 96		return errors.KeyInvalidError("ed448: invalid ed448 secret")
 97	}
 98	if subtle.ConstantTimeCompare(priv.PublicKey.Point, expectedPrivateKey[SeedSize:]) == 0 {
 99		return errors.KeyInvalidError("ed448: invalid ed448 public key")
100	}
101	return nil
102}
103
104// ENCODING/DECODING signature:
105
106// WriteSignature encodes and writes an ed448 signature to writer.
107func WriteSignature(writer io.Writer, signature []byte) error {
108	_, err := writer.Write(signature)
109	return err
110}
111
112// ReadSignature decodes an ed448 signature from a reader.
113func ReadSignature(reader io.Reader) ([]byte, error) {
114	signature := make([]byte, SignatureSize)
115	if _, err := io.ReadFull(reader, signature); err != nil {
116		return nil, err
117	}
118	return signature, nil
119}