github.com/cloudflare/circl@v1.5.0/sign/eddilithium3/eddilithium.go (about)

     1  // Package eddilithium3 implements the hybrid signature scheme Ed448-Dilithium3.
     2  package eddilithium3
     3  
     4  import (
     5  	"crypto"
     6  	cryptoRand "crypto/rand"
     7  	"errors"
     8  	"io"
     9  
    10  	"github.com/cloudflare/circl/internal/sha3"
    11  	"github.com/cloudflare/circl/sign"
    12  	"github.com/cloudflare/circl/sign/dilithium/mode3"
    13  	"github.com/cloudflare/circl/sign/ed448"
    14  )
    15  
    16  const (
    17  	// SeedSize is the length of the seed for NewKeyFromSeed
    18  	SeedSize = ed448.SeedSize // > mode3.SeedSize
    19  
    20  	// PublicKeySize is the length in bytes of the packed public key.
    21  	PublicKeySize = mode3.PublicKeySize + ed448.PublicKeySize
    22  
    23  	// PrivateKeySize is the length in bytes of the packed public key.
    24  	PrivateKeySize = mode3.PrivateKeySize + ed448.SeedSize
    25  
    26  	// SignatureSize is the length in bytes of the signatures.
    27  	SignatureSize = mode3.SignatureSize + ed448.SignatureSize
    28  )
    29  
    30  // PublicKey is the type of an EdDilithium3 public key.
    31  type PublicKey struct {
    32  	e ed448.PublicKey
    33  	d mode3.PublicKey
    34  }
    35  
    36  // PrivateKey is the type of an EdDilithium3 private key.
    37  type PrivateKey struct {
    38  	e ed448.PrivateKey
    39  	d mode3.PrivateKey
    40  }
    41  
    42  // GenerateKey generates a public/private key pair using entropy from rand.
    43  // If rand is nil, crypto/rand.Reader will be used.
    44  func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) {
    45  	var seed [SeedSize]byte
    46  	if rand == nil {
    47  		rand = cryptoRand.Reader
    48  	}
    49  	_, err := io.ReadFull(rand, seed[:])
    50  	if err != nil {
    51  		return nil, nil, err
    52  	}
    53  
    54  	pk, sk := NewKeyFromSeed(&seed)
    55  	return pk, sk, nil
    56  }
    57  
    58  // NewKeyFromSeed derives a public/private key pair using the given seed.
    59  func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) {
    60  	var seed1 [32]byte
    61  	var seed2 [ed448.SeedSize]byte
    62  
    63  	h := sha3.NewShake256()
    64  	_, _ = h.Write(seed[:])
    65  	_, _ = h.Read(seed1[:])
    66  	_, _ = h.Read(seed2[:])
    67  	dpk, dsk := mode3.NewKeyFromSeed(&seed1)
    68  	esk := ed448.NewKeyFromSeed(seed2[:])
    69  
    70  	return &PublicKey{esk.Public().(ed448.PublicKey), *dpk}, &PrivateKey{esk, *dsk}
    71  }
    72  
    73  // SignTo signs the given message and writes the signature into signature.
    74  // It will panic if signature is not of length at least SignatureSize.
    75  func SignTo(sk *PrivateKey, msg []byte, signature []byte) {
    76  	mode3.SignTo(
    77  		&sk.d,
    78  		msg,
    79  		signature[:mode3.SignatureSize],
    80  	)
    81  	esig := ed448.Sign(
    82  		sk.e,
    83  		msg,
    84  		"",
    85  	)
    86  	copy(signature[mode3.SignatureSize:], esig[:])
    87  }
    88  
    89  // Verify checks whether the given signature by pk on msg is valid.
    90  func Verify(pk *PublicKey, msg []byte, signature []byte) bool {
    91  	if !mode3.Verify(
    92  		&pk.d,
    93  		msg,
    94  		signature[:mode3.SignatureSize],
    95  	) {
    96  		return false
    97  	}
    98  	if !ed448.Verify(
    99  		pk.e,
   100  		msg,
   101  		signature[mode3.SignatureSize:],
   102  		"",
   103  	) {
   104  		return false
   105  	}
   106  	return true
   107  }
   108  
   109  // Unpack unpacks pk to the public key encoded in buf.
   110  func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) {
   111  	var tmp [mode3.PublicKeySize]byte
   112  	copy(tmp[:], buf[:mode3.PublicKeySize])
   113  	pk.d.Unpack(&tmp)
   114  	pk.e = make([]byte, ed448.PublicKeySize)
   115  	copy(pk.e, buf[mode3.PublicKeySize:])
   116  }
   117  
   118  // Unpack sets sk to the private key encoded in buf.
   119  func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) {
   120  	var tmp [mode3.PrivateKeySize]byte
   121  	copy(tmp[:], buf[:mode3.PrivateKeySize])
   122  	sk.d.Unpack(&tmp)
   123  	sk.e = ed448.NewKeyFromSeed(buf[mode3.PrivateKeySize:])
   124  }
   125  
   126  // Pack packs the public key into buf.
   127  func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) {
   128  	var tmp [mode3.PublicKeySize]byte
   129  	pk.d.Pack(&tmp)
   130  	copy(buf[:mode3.PublicKeySize], tmp[:])
   131  	copy(buf[mode3.PublicKeySize:], pk.e)
   132  }
   133  
   134  // Pack packs the private key into buf.
   135  func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) {
   136  	var tmp [mode3.PrivateKeySize]byte
   137  	sk.d.Pack(&tmp)
   138  	copy(buf[:mode3.PrivateKeySize], tmp[:])
   139  	copy(buf[mode3.PrivateKeySize:], sk.e.Seed())
   140  }
   141  
   142  // Bytes packs the public key.
   143  func (pk *PublicKey) Bytes() []byte {
   144  	return append(pk.d.Bytes(), pk.e...)
   145  }
   146  
   147  // Bytes packs the private key.
   148  func (sk *PrivateKey) Bytes() []byte {
   149  	return append(sk.d.Bytes(), sk.e.Seed()...)
   150  }
   151  
   152  // MarshalBinary packs the public key.
   153  func (pk *PublicKey) MarshalBinary() ([]byte, error) {
   154  	return pk.Bytes(), nil
   155  }
   156  
   157  // MarshalBinary packs the private key.
   158  func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
   159  	return sk.Bytes(), nil
   160  }
   161  
   162  // UnmarshalBinary the public key from data.
   163  func (pk *PublicKey) UnmarshalBinary(data []byte) error {
   164  	if len(data) != PublicKeySize {
   165  		return errors.New("packed public key must be of eddilithium3.PublicKeySize bytes")
   166  	}
   167  	var buf [PublicKeySize]byte
   168  	copy(buf[:], data)
   169  	pk.Unpack(&buf)
   170  	return nil
   171  }
   172  
   173  // UnmarshalBinary unpacks the private key from data.
   174  func (sk *PrivateKey) UnmarshalBinary(data []byte) error {
   175  	if len(data) != PrivateKeySize {
   176  		return errors.New("packed private key must be of eddilithium3.PrivateKeySize bytes")
   177  	}
   178  	var buf [PrivateKeySize]byte
   179  	copy(buf[:], data)
   180  	sk.Unpack(&buf)
   181  	return nil
   182  }
   183  
   184  func (sk *PrivateKey) Scheme() sign.Scheme { return sch }
   185  func (pk *PublicKey) Scheme() sign.Scheme  { return sch }
   186  
   187  func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool {
   188  	castOther, ok := other.(*PrivateKey)
   189  	if !ok {
   190  		return false
   191  	}
   192  	return castOther.e.Equal(sk.e) && castOther.d.Equal(&sk.d)
   193  }
   194  
   195  func (pk *PublicKey) Equal(other crypto.PublicKey) bool {
   196  	castOther, ok := other.(*PublicKey)
   197  	if !ok {
   198  		return false
   199  	}
   200  	return castOther.e.Equal(pk.e) && castOther.d.Equal(&pk.d)
   201  }
   202  
   203  // Sign signs the given message.
   204  //
   205  // opts.HashFunc() must return zero, which can be achieved by passing
   206  // crypto.Hash(0) for opts.  rand is ignored.  Will only return an error
   207  // if opts.HashFunc() is non-zero.
   208  //
   209  // This function is used to make PrivateKey implement the crypto.Signer
   210  // interface.  The package-level SignTo function might be more convenient
   211  // to use.
   212  func (sk *PrivateKey) Sign(
   213  	rand io.Reader, msg []byte, opts crypto.SignerOpts,
   214  ) (signature []byte, err error) {
   215  	var sig [SignatureSize]byte
   216  
   217  	if opts.HashFunc() != crypto.Hash(0) {
   218  		return nil, errors.New("eddilithium3: cannot sign hashed message")
   219  	}
   220  
   221  	SignTo(sk, msg, sig[:])
   222  	return sig[:], nil
   223  }
   224  
   225  // Public computes the public key corresponding to this private key.
   226  //
   227  // Returns a *PublicKey.  The type crypto.PublicKey is used to make
   228  // PrivateKey implement the crypto.Signer interface.
   229  func (sk *PrivateKey) Public() crypto.PublicKey {
   230  	return &PublicKey{
   231  		sk.e.Public().(ed448.PublicKey),
   232  		*sk.d.Public().(*mode3.PublicKey),
   233  	}
   234  }