main
Raw Download raw file
  1// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
  2package ecc
  3
  4import (
  5	"crypto/subtle"
  6	"io"
  7
  8	"github.com/ProtonMail/go-crypto/openpgp/errors"
  9	x448lib "github.com/cloudflare/circl/dh/x448"
 10)
 11
 12type x448 struct{}
 13
 14func NewX448() *x448 {
 15	return &x448{}
 16}
 17
 18func (c *x448) GetCurveName() string {
 19	return "x448"
 20}
 21
 22// MarshalBytePoint encodes the public point from native format, adding the prefix.
 23// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
 24func (c *x448) MarshalBytePoint(point []byte) []byte {
 25	return append([]byte{0x40}, point...)
 26}
 27
 28// UnmarshalBytePoint decodes a point from prefixed format to native.
 29// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
 30func (c *x448) UnmarshalBytePoint(point []byte) []byte {
 31	if len(point) != x448lib.Size+1 {
 32		return nil
 33	}
 34
 35	return point[1:]
 36}
 37
 38// MarshalByteSecret encoded a scalar from native format to prefixed.
 39// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
 40func (c *x448) MarshalByteSecret(d []byte) []byte {
 41	return append([]byte{0x40}, d...)
 42}
 43
 44// UnmarshalByteSecret decodes a scalar from prefixed format to native.
 45// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
 46func (c *x448) UnmarshalByteSecret(d []byte) []byte {
 47	if len(d) != x448lib.Size+1 {
 48		return nil
 49	}
 50
 51	// Store without prefix
 52	return d[1:]
 53}
 54
 55func (c *x448) generateKeyPairBytes(rand io.Reader) (sk, pk x448lib.Key, err error) {
 56	if _, err = rand.Read(sk[:]); err != nil {
 57		return
 58	}
 59
 60	x448lib.KeyGen(&pk, &sk)
 61	return
 62}
 63
 64func (c *x448) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) {
 65	priv, pub, err := c.generateKeyPairBytes(rand)
 66	if err != nil {
 67		return
 68	}
 69
 70	return pub[:], priv[:], nil
 71}
 72
 73func (c *x448) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
 74	var pk, ss x448lib.Key
 75	seed, e, err := c.generateKeyPairBytes(rand)
 76	if err != nil {
 77		return nil, nil, err
 78	}
 79	copy(pk[:], point)
 80	x448lib.Shared(&ss, &seed, &pk)
 81
 82	return e[:], ss[:], nil
 83}
 84
 85func (c *x448) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
 86	var ss, sk, e x448lib.Key
 87
 88	copy(sk[:], secret)
 89	copy(e[:], ephemeral)
 90	x448lib.Shared(&ss, &sk, &e)
 91
 92	return ss[:], nil
 93}
 94
 95func (c *x448) ValidateECDH(point []byte, secret []byte) error {
 96	var sk, pk, expectedPk x448lib.Key
 97
 98	copy(pk[:], point)
 99	copy(sk[:], secret)
100	x448lib.KeyGen(&expectedPk, &sk)
101
102	if subtle.ConstantTimeCompare(expectedPk[:], pk[:]) == 0 {
103		return errors.KeyInvalidError("ecc: invalid curve25519 public point")
104	}
105
106	return nil
107}