mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 19:39:58 +00:00
RTG-1339 Support post-quantum hybrid key exchange
Func spec: https://wiki.cfops.it/x/ZcBKHw
This commit is contained in:

committed by
Devin Carr

parent
3e0ff3a771
commit
11cbff4ff7
335
vendor/github.com/cloudflare/circl/kem/hybrid/hybrid.go
generated
vendored
Normal file
335
vendor/github.com/cloudflare/circl/kem/hybrid/hybrid.go
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
// Package hybrid defines several hybrid classical/quantum KEMs.
|
||||
//
|
||||
// KEMs are combined by simple concatenation of shared secrets, cipher texts,
|
||||
// public keys, etc, see
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/
|
||||
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Cr2.pdf
|
||||
//
|
||||
// Note that this is only fine if the shared secret is used in its entirety
|
||||
// in a next step, such as being hashed or used as key.
|
||||
//
|
||||
// For deriving a KEM keypair deterministically and encapsulating
|
||||
// deterministically, we expand a single seed to both using SHAKE256,
|
||||
// so that a non-uniform seed (such as a shared secret generated by a hybrid
|
||||
// KEM where one of the KEMs is weak) doesn't impact just one of the KEMs.
|
||||
//
|
||||
// Of our XOF (SHAKE256), we desire two security properties:
|
||||
//
|
||||
// 1. The internal state of the XOF should be big enough so that we
|
||||
// do not loose entropy.
|
||||
// 2. From one of the new seeds, we shouldn't be able to derive
|
||||
// the other or the original seed.
|
||||
//
|
||||
// SHAKE256, and all siblings in the SHA3 family, have a 200B internal
|
||||
// state, so (1) is fine if our seeds are less than 200B.
|
||||
// If SHAKE256 is computationally indistinguishable from a random
|
||||
// sponge, then it affords us 256b security against (2) by the
|
||||
// flat sponge claim [https://keccak.team/files/SpongeFunctions.pdf].
|
||||
// None of the implemented schemes claim more than 256b security
|
||||
// and so SHAKE256 will do fine.
|
||||
package hybrid
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/cloudflare/circl/internal/sha3"
|
||||
"github.com/cloudflare/circl/kem"
|
||||
"github.com/cloudflare/circl/kem/kyber/kyber1024"
|
||||
"github.com/cloudflare/circl/kem/kyber/kyber512"
|
||||
"github.com/cloudflare/circl/kem/kyber/kyber768"
|
||||
)
|
||||
|
||||
var ErrUninitialized = errors.New("public or private key not initialized")
|
||||
|
||||
// Returns the hybrid KEM of Kyber512 and X25519.
|
||||
func Kyber512X25519() kem.Scheme { return kyber512X }
|
||||
|
||||
// Returns the hybrid KEM of Kyber768 and X25519.
|
||||
func Kyber768X25519() kem.Scheme { return kyber768X }
|
||||
|
||||
// Returns the hybrid KEM of Kyber768 and X448.
|
||||
func Kyber768X448() kem.Scheme { return kyber768X4 }
|
||||
|
||||
// Returns the hybrid KEM of Kyber1024 and X448.
|
||||
func Kyber1024X448() kem.Scheme { return kyber1024X }
|
||||
|
||||
var kyber512X kem.Scheme = &scheme{
|
||||
"Kyber512-X25519",
|
||||
x25519Kem,
|
||||
kyber512.Scheme(),
|
||||
}
|
||||
|
||||
var kyber768X kem.Scheme = &scheme{
|
||||
"Kyber768-X25519",
|
||||
x25519Kem,
|
||||
kyber768.Scheme(),
|
||||
}
|
||||
|
||||
var kyber768X4 kem.Scheme = &scheme{
|
||||
"Kyber768-X448",
|
||||
x448Kem,
|
||||
kyber768.Scheme(),
|
||||
}
|
||||
|
||||
var kyber1024X kem.Scheme = &scheme{
|
||||
"Kyber1024-X448",
|
||||
x448Kem,
|
||||
kyber1024.Scheme(),
|
||||
}
|
||||
|
||||
// Public key of a hybrid KEM.
|
||||
type publicKey struct {
|
||||
scheme *scheme
|
||||
first kem.PublicKey
|
||||
second kem.PublicKey
|
||||
}
|
||||
|
||||
// Private key of a hybrid KEM.
|
||||
type privateKey struct {
|
||||
scheme *scheme
|
||||
first kem.PrivateKey
|
||||
second kem.PrivateKey
|
||||
}
|
||||
|
||||
// Scheme for a hybrid KEM.
|
||||
type scheme struct {
|
||||
name string
|
||||
first kem.Scheme
|
||||
second kem.Scheme
|
||||
}
|
||||
|
||||
func (sch *scheme) Name() string { return sch.name }
|
||||
func (sch *scheme) PublicKeySize() int {
|
||||
return sch.first.PublicKeySize() + sch.second.PublicKeySize()
|
||||
}
|
||||
|
||||
func (sch *scheme) PrivateKeySize() int {
|
||||
return sch.first.PrivateKeySize() + sch.second.PrivateKeySize()
|
||||
}
|
||||
|
||||
func (sch *scheme) SeedSize() int {
|
||||
first := sch.first.SeedSize()
|
||||
second := sch.second.SeedSize()
|
||||
ret := second
|
||||
if first > second {
|
||||
ret = first
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (sch *scheme) SharedKeySize() int {
|
||||
return sch.first.SharedKeySize() + sch.second.SharedKeySize()
|
||||
}
|
||||
|
||||
func (sch *scheme) CiphertextSize() int {
|
||||
return sch.first.CiphertextSize() + sch.second.CiphertextSize()
|
||||
}
|
||||
|
||||
func (sch *scheme) EncapsulationSeedSize() int {
|
||||
first := sch.first.EncapsulationSeedSize()
|
||||
second := sch.second.EncapsulationSeedSize()
|
||||
ret := second
|
||||
if first > second {
|
||||
ret = first
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (sk *privateKey) Scheme() kem.Scheme { return sk.scheme }
|
||||
func (pk *publicKey) Scheme() kem.Scheme { return pk.scheme }
|
||||
|
||||
func (sk *privateKey) MarshalBinary() ([]byte, error) {
|
||||
if sk.first == nil || sk.second == nil {
|
||||
return nil, ErrUninitialized
|
||||
}
|
||||
first, err := sk.first.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
second, err := sk.second.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(first, second...), nil
|
||||
}
|
||||
|
||||
func (sk *privateKey) Equal(other kem.PrivateKey) bool {
|
||||
oth, ok := other.(*privateKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if sk.first == nil && sk.second == nil && oth.first == nil && oth.second == nil {
|
||||
return true
|
||||
}
|
||||
if sk.first == nil || sk.second == nil || oth.first == nil || oth.second == nil {
|
||||
return false
|
||||
}
|
||||
return sk.first.Equal(oth.first) && sk.second.Equal(oth.second)
|
||||
}
|
||||
|
||||
func (sk *privateKey) Public() kem.PublicKey {
|
||||
return &publicKey{sk.scheme, sk.first.Public(), sk.second.Public()}
|
||||
}
|
||||
|
||||
func (pk *publicKey) Equal(other kem.PublicKey) bool {
|
||||
oth, ok := other.(*publicKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if pk.first == nil && pk.second == nil && oth.first == nil && oth.second == nil {
|
||||
return true
|
||||
}
|
||||
if pk.first == nil || pk.second == nil || oth.first == nil || oth.second == nil {
|
||||
return false
|
||||
}
|
||||
return pk.first.Equal(oth.first) && pk.second.Equal(oth.second)
|
||||
}
|
||||
|
||||
func (pk *publicKey) MarshalBinary() ([]byte, error) {
|
||||
if pk.first == nil || pk.second == nil {
|
||||
return nil, ErrUninitialized
|
||||
}
|
||||
first, err := pk.first.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
second, err := pk.second.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(first, second...), nil
|
||||
}
|
||||
|
||||
func (sch *scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
|
||||
pk1, sk1, err := sch.first.GenerateKeyPair()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk2, sk2, err := sch.second.GenerateKeyPair()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &publicKey{sch, pk1, pk2}, &privateKey{sch, sk1, sk2}, nil
|
||||
}
|
||||
|
||||
func (sch *scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
|
||||
if len(seed) != sch.SeedSize() {
|
||||
panic(kem.ErrSeedSize)
|
||||
}
|
||||
h := sha3.NewShake256()
|
||||
_, _ = h.Write(seed)
|
||||
first := make([]byte, sch.first.SeedSize())
|
||||
second := make([]byte, sch.second.SeedSize())
|
||||
_, _ = h.Read(first)
|
||||
_, _ = h.Read(second)
|
||||
|
||||
pk1, sk1 := sch.first.DeriveKeyPair(first)
|
||||
pk2, sk2 := sch.second.DeriveKeyPair(second)
|
||||
|
||||
return &publicKey{sch, pk1, pk2}, &privateKey{sch, sk1, sk2}
|
||||
}
|
||||
|
||||
func (sch *scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
|
||||
pub, ok := pk.(*publicKey)
|
||||
if !ok {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
|
||||
ct1, ss1, err := sch.first.Encapsulate(pub.first)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ct2, ss2, err := sch.second.Encapsulate(pub.second)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return append(ct1, ct2...), append(ss1, ss2...), nil
|
||||
}
|
||||
|
||||
func (sch *scheme) EncapsulateDeterministically(
|
||||
pk kem.PublicKey, seed []byte,
|
||||
) (ct, ss []byte, err error) {
|
||||
if len(seed) != sch.EncapsulationSeedSize() {
|
||||
return nil, nil, kem.ErrSeedSize
|
||||
}
|
||||
|
||||
h := sha3.NewShake256()
|
||||
_, _ = h.Write(seed)
|
||||
first := make([]byte, sch.first.EncapsulationSeedSize())
|
||||
second := make([]byte, sch.second.EncapsulationSeedSize())
|
||||
_, _ = h.Read(first)
|
||||
_, _ = h.Read(second)
|
||||
|
||||
pub, ok := pk.(*publicKey)
|
||||
if !ok {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
|
||||
ct1, ss1, err := sch.first.EncapsulateDeterministically(pub.first, first)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ct2, ss2, err := sch.second.EncapsulateDeterministically(pub.second, second)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return append(ct1, ct2...), append(ss1, ss2...), nil
|
||||
}
|
||||
|
||||
func (sch *scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
|
||||
if len(ct) != sch.CiphertextSize() {
|
||||
return nil, kem.ErrCiphertextSize
|
||||
}
|
||||
|
||||
priv, ok := sk.(*privateKey)
|
||||
if !ok {
|
||||
return nil, kem.ErrTypeMismatch
|
||||
}
|
||||
|
||||
firstSize := sch.first.CiphertextSize()
|
||||
ss1, err := sch.first.Decapsulate(priv.first, ct[:firstSize])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ss2, err := sch.second.Decapsulate(priv.second, ct[firstSize:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(ss1, ss2...), nil
|
||||
}
|
||||
|
||||
func (sch *scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
|
||||
if len(buf) != sch.PublicKeySize() {
|
||||
return nil, kem.ErrPubKeySize
|
||||
}
|
||||
firstSize := sch.first.PublicKeySize()
|
||||
pk1, err := sch.first.UnmarshalBinaryPublicKey(buf[:firstSize])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pk2, err := sch.second.UnmarshalBinaryPublicKey(buf[firstSize:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &publicKey{sch, pk1, pk2}, nil
|
||||
}
|
||||
|
||||
func (sch *scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
|
||||
if len(buf) != sch.PrivateKeySize() {
|
||||
return nil, kem.ErrPrivKeySize
|
||||
}
|
||||
firstSize := sch.first.PrivateKeySize()
|
||||
sk1, err := sch.first.UnmarshalBinaryPrivateKey(buf[:firstSize])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sk2, err := sch.second.UnmarshalBinaryPrivateKey(buf[firstSize:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &privateKey{sch, sk1, sk2}, nil
|
||||
}
|
208
vendor/github.com/cloudflare/circl/kem/hybrid/xkem.go
generated
vendored
Normal file
208
vendor/github.com/cloudflare/circl/kem/hybrid/xkem.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
package hybrid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
cryptoRand "crypto/rand"
|
||||
"crypto/subtle"
|
||||
|
||||
"github.com/cloudflare/circl/dh/x25519"
|
||||
"github.com/cloudflare/circl/dh/x448"
|
||||
"github.com/cloudflare/circl/internal/sha3"
|
||||
"github.com/cloudflare/circl/kem"
|
||||
)
|
||||
|
||||
type xPublicKey struct {
|
||||
scheme *xScheme
|
||||
key []byte
|
||||
}
|
||||
type xPrivateKey struct {
|
||||
scheme *xScheme
|
||||
key []byte
|
||||
}
|
||||
type xScheme struct {
|
||||
size int
|
||||
}
|
||||
|
||||
var (
|
||||
x25519Kem = &xScheme{x25519.Size}
|
||||
x448Kem = &xScheme{x448.Size}
|
||||
)
|
||||
|
||||
func (sch *xScheme) Name() string {
|
||||
switch sch.size {
|
||||
case x25519.Size:
|
||||
return "X25519"
|
||||
case x448.Size:
|
||||
return "X448"
|
||||
}
|
||||
panic(kem.ErrTypeMismatch)
|
||||
}
|
||||
|
||||
func (sch *xScheme) PublicKeySize() int { return sch.size }
|
||||
func (sch *xScheme) PrivateKeySize() int { return sch.size }
|
||||
func (sch *xScheme) SeedSize() int { return sch.size }
|
||||
func (sch *xScheme) SharedKeySize() int { return sch.size }
|
||||
func (sch *xScheme) CiphertextSize() int { return sch.size }
|
||||
func (sch *xScheme) EncapsulationSeedSize() int { return sch.size }
|
||||
|
||||
func (sk *xPrivateKey) Scheme() kem.Scheme { return sk.scheme }
|
||||
func (pk *xPublicKey) Scheme() kem.Scheme { return pk.scheme }
|
||||
|
||||
func (sk *xPrivateKey) MarshalBinary() ([]byte, error) {
|
||||
ret := make([]byte, len(sk.key))
|
||||
copy(ret, sk.key)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (sk *xPrivateKey) Equal(other kem.PrivateKey) bool {
|
||||
oth, ok := other.(*xPrivateKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if oth.scheme != sk.scheme {
|
||||
return false
|
||||
}
|
||||
return subtle.ConstantTimeCompare(oth.key, sk.key) == 1
|
||||
}
|
||||
|
||||
func (sk *xPrivateKey) Public() kem.PublicKey {
|
||||
pk := xPublicKey{sk.scheme, make([]byte, sk.scheme.size)}
|
||||
switch sk.scheme.size {
|
||||
case x25519.Size:
|
||||
var sk2, pk2 x25519.Key
|
||||
copy(sk2[:], sk.key)
|
||||
x25519.KeyGen(&pk2, &sk2)
|
||||
copy(pk.key, pk2[:])
|
||||
case x448.Size:
|
||||
var sk2, pk2 x448.Key
|
||||
copy(sk2[:], sk.key)
|
||||
x448.KeyGen(&pk2, &sk2)
|
||||
copy(pk.key, pk2[:])
|
||||
}
|
||||
return &pk
|
||||
}
|
||||
|
||||
func (pk *xPublicKey) Equal(other kem.PublicKey) bool {
|
||||
oth, ok := other.(*xPublicKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if oth.scheme != pk.scheme {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(oth.key, pk.key)
|
||||
}
|
||||
|
||||
func (pk *xPublicKey) MarshalBinary() ([]byte, error) {
|
||||
ret := make([]byte, pk.scheme.size)
|
||||
copy(ret, pk.key)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (sch *xScheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
|
||||
seed := make([]byte, sch.SeedSize())
|
||||
_, err := cryptoRand.Read(seed)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk, sk := sch.DeriveKeyPair(seed)
|
||||
return pk, sk, nil
|
||||
}
|
||||
|
||||
func (sch *xScheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
|
||||
if len(seed) != sch.SeedSize() {
|
||||
panic(kem.ErrSeedSize)
|
||||
}
|
||||
sk := xPrivateKey{scheme: sch, key: make([]byte, sch.size)}
|
||||
|
||||
h := sha3.NewShake256()
|
||||
_, _ = h.Write(seed)
|
||||
_, _ = h.Read(sk.key)
|
||||
|
||||
return sk.Public(), &sk
|
||||
}
|
||||
|
||||
func (sch *xScheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
|
||||
seed := make([]byte, sch.EncapsulationSeedSize())
|
||||
_, err = cryptoRand.Read(seed)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return sch.EncapsulateDeterministically(pk, seed)
|
||||
}
|
||||
|
||||
func (pk *xPublicKey) X(sk *xPrivateKey) []byte {
|
||||
if pk.scheme != sk.scheme {
|
||||
panic(kem.ErrTypeMismatch)
|
||||
}
|
||||
|
||||
switch pk.scheme.size {
|
||||
case x25519.Size:
|
||||
var ss2, pk2, sk2 x25519.Key
|
||||
copy(pk2[:], pk.key)
|
||||
copy(sk2[:], sk.key)
|
||||
x25519.Shared(&ss2, &sk2, &pk2)
|
||||
return ss2[:]
|
||||
case x448.Size:
|
||||
var ss2, pk2, sk2 x448.Key
|
||||
copy(pk2[:], pk.key)
|
||||
copy(sk2[:], sk.key)
|
||||
x448.Shared(&ss2, &sk2, &pk2)
|
||||
return ss2[:]
|
||||
}
|
||||
panic(kem.ErrTypeMismatch)
|
||||
}
|
||||
|
||||
func (sch *xScheme) EncapsulateDeterministically(
|
||||
pk kem.PublicKey, seed []byte,
|
||||
) (ct, ss []byte, err error) {
|
||||
if len(seed) != sch.EncapsulationSeedSize() {
|
||||
return nil, nil, kem.ErrSeedSize
|
||||
}
|
||||
pub, ok := pk.(*xPublicKey)
|
||||
if !ok || pub.scheme != sch {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
|
||||
pk2, sk2 := sch.DeriveKeyPair(seed)
|
||||
ss = pub.X(sk2.(*xPrivateKey))
|
||||
ct, _ = pk2.MarshalBinary()
|
||||
return
|
||||
}
|
||||
|
||||
func (sch *xScheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
|
||||
if len(ct) != sch.CiphertextSize() {
|
||||
return nil, kem.ErrCiphertextSize
|
||||
}
|
||||
|
||||
priv, ok := sk.(*xPrivateKey)
|
||||
if !ok || priv.scheme != sch {
|
||||
return nil, kem.ErrTypeMismatch
|
||||
}
|
||||
|
||||
pk, err := sch.UnmarshalBinaryPublicKey(ct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ss := pk.(*xPublicKey).X(priv)
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func (sch *xScheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
|
||||
if len(buf) != sch.PublicKeySize() {
|
||||
return nil, kem.ErrPubKeySize
|
||||
}
|
||||
ret := xPublicKey{sch, make([]byte, sch.size)}
|
||||
copy(ret.key, buf)
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (sch *xScheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
|
||||
if len(buf) != sch.PrivateKeySize() {
|
||||
return nil, kem.ErrPrivKeySize
|
||||
}
|
||||
ret := xPrivateKey{sch, make([]byte, sch.size)}
|
||||
copy(ret.key, buf)
|
||||
return &ret, nil
|
||||
}
|
118
vendor/github.com/cloudflare/circl/kem/kem.go
generated
vendored
Normal file
118
vendor/github.com/cloudflare/circl/kem/kem.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
// Package kem provides a unified interface for KEM schemes.
|
||||
//
|
||||
// A register of schemes is available in the package
|
||||
//
|
||||
// github.com/cloudflare/circl/kem/schemes
|
||||
package kem
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// A KEM public key
|
||||
type PublicKey interface {
|
||||
// Returns the scheme for this public key
|
||||
Scheme() Scheme
|
||||
|
||||
encoding.BinaryMarshaler
|
||||
Equal(PublicKey) bool
|
||||
}
|
||||
|
||||
// A KEM private key
|
||||
type PrivateKey interface {
|
||||
// Returns the scheme for this private key
|
||||
Scheme() Scheme
|
||||
|
||||
encoding.BinaryMarshaler
|
||||
Equal(PrivateKey) bool
|
||||
Public() PublicKey
|
||||
}
|
||||
|
||||
// A Scheme represents a specific instance of a KEM.
|
||||
type Scheme interface {
|
||||
// Name of the scheme
|
||||
Name() string
|
||||
|
||||
// GenerateKeyPair creates a new key pair.
|
||||
GenerateKeyPair() (PublicKey, PrivateKey, error)
|
||||
|
||||
// Encapsulate generates a shared key ss for the public key and
|
||||
// encapsulates it into a ciphertext ct.
|
||||
Encapsulate(pk PublicKey) (ct, ss []byte, err error)
|
||||
|
||||
// Returns the shared key encapsulated in ciphertext ct for the
|
||||
// private key sk.
|
||||
Decapsulate(sk PrivateKey, ct []byte) ([]byte, error)
|
||||
|
||||
// Unmarshals a PublicKey from the provided buffer.
|
||||
UnmarshalBinaryPublicKey([]byte) (PublicKey, error)
|
||||
|
||||
// Unmarshals a PrivateKey from the provided buffer.
|
||||
UnmarshalBinaryPrivateKey([]byte) (PrivateKey, error)
|
||||
|
||||
// Size of encapsulated keys.
|
||||
CiphertextSize() int
|
||||
|
||||
// Size of established shared keys.
|
||||
SharedKeySize() int
|
||||
|
||||
// Size of packed private keys.
|
||||
PrivateKeySize() int
|
||||
|
||||
// Size of packed public keys.
|
||||
PublicKeySize() int
|
||||
|
||||
// DeriveKeyPair deterministicallly derives a pair of keys from a seed.
|
||||
// Panics if the length of seed is not equal to the value returned by
|
||||
// SeedSize.
|
||||
DeriveKeyPair(seed []byte) (PublicKey, PrivateKey)
|
||||
|
||||
// Size of seed used in DeriveKey
|
||||
SeedSize() int
|
||||
|
||||
// EncapsulateDeterministically generates a shared key ss for the public
|
||||
// key deterministically from the given seed and encapsulates it into
|
||||
// a ciphertext ct. If unsure, you're better off using Encapsulate().
|
||||
EncapsulateDeterministically(pk PublicKey, seed []byte) (
|
||||
ct, ss []byte, err error)
|
||||
|
||||
// Size of seed used in EncapsulateDeterministically().
|
||||
EncapsulationSeedSize() int
|
||||
}
|
||||
|
||||
// AuthScheme represents a KEM that supports authenticated key encapsulation.
|
||||
type AuthScheme interface {
|
||||
Scheme
|
||||
AuthEncapsulate(pkr PublicKey, sks PrivateKey) (ct, ss []byte, err error)
|
||||
AuthEncapsulateDeterministically(pkr PublicKey, sks PrivateKey, seed []byte) (ct, ss []byte, err error)
|
||||
AuthDecapsulate(skr PrivateKey, ct []byte, pks PublicKey) ([]byte, error)
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrTypeMismatch is the error used if types of, for instance, private
|
||||
// and public keys don't match
|
||||
ErrTypeMismatch = errors.New("types mismatch")
|
||||
|
||||
// ErrSeedSize is the error used if the provided seed is of the wrong
|
||||
// size.
|
||||
ErrSeedSize = errors.New("wrong seed size")
|
||||
|
||||
// ErrPubKeySize is the error used if the provided public key is of
|
||||
// the wrong size.
|
||||
ErrPubKeySize = errors.New("wrong size for public key")
|
||||
|
||||
// ErrCiphertextSize is the error used if the provided ciphertext
|
||||
// is of the wrong size.
|
||||
ErrCiphertextSize = errors.New("wrong size for ciphertext")
|
||||
|
||||
// ErrPrivKeySize is the error used if the provided private key is of
|
||||
// the wrong size.
|
||||
ErrPrivKeySize = errors.New("wrong size for private key")
|
||||
|
||||
// ErrPubKey is the error used if the provided public key is invalid.
|
||||
ErrPubKey = errors.New("invalid public key")
|
||||
|
||||
// ErrCipherText is the error used if the provided ciphertext is invalid.
|
||||
ErrCipherText = errors.New("invalid ciphertext")
|
||||
)
|
402
vendor/github.com/cloudflare/circl/kem/kyber/kyber1024/kyber.go
generated
vendored
Normal file
402
vendor/github.com/cloudflare/circl/kem/kyber/kyber1024/kyber.go
generated
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
// Code generated from pkg.templ.go. DO NOT EDIT.
|
||||
|
||||
// Package kyber1024 implements the IND-CCA2 secure key encapsulation mechanism
|
||||
// Kyber1024.CCAKEM as submitted to round 3 of the NIST PQC competition and
|
||||
// described in
|
||||
//
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf
|
||||
package kyber1024
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/subtle"
|
||||
"io"
|
||||
|
||||
cryptoRand "crypto/rand"
|
||||
"github.com/cloudflare/circl/internal/sha3"
|
||||
"github.com/cloudflare/circl/kem"
|
||||
cpapke "github.com/cloudflare/circl/pke/kyber/kyber1024"
|
||||
)
|
||||
|
||||
const (
|
||||
// Size of seed for NewKeyFromSeed
|
||||
KeySeedSize = cpapke.KeySeedSize + 32
|
||||
|
||||
// Size of seed for EncapsulateTo.
|
||||
EncapsulationSeedSize = 32
|
||||
|
||||
// Size of the established shared key.
|
||||
SharedKeySize = 32
|
||||
|
||||
// Size of the encapsulated shared key.
|
||||
CiphertextSize = cpapke.CiphertextSize
|
||||
|
||||
// Size of a packed public key.
|
||||
PublicKeySize = cpapke.PublicKeySize
|
||||
|
||||
// Size of a packed private key.
|
||||
PrivateKeySize = cpapke.PrivateKeySize + cpapke.PublicKeySize + 64
|
||||
)
|
||||
|
||||
// Type of a Kyber1024.CCAKEM public key
|
||||
type PublicKey struct {
|
||||
pk *cpapke.PublicKey
|
||||
|
||||
hpk [32]byte // H(pk)
|
||||
}
|
||||
|
||||
// Type of a Kyber1024.CCAKEM private key
|
||||
type PrivateKey struct {
|
||||
sk *cpapke.PrivateKey
|
||||
pk *cpapke.PublicKey
|
||||
hpk [32]byte // H(pk)
|
||||
z [32]byte
|
||||
}
|
||||
|
||||
// NewKeyFromSeed derives a public/private keypair deterministically
|
||||
// from the given seed.
|
||||
//
|
||||
// Panics if seed is not of length KeySeedSize.
|
||||
func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) {
|
||||
var sk PrivateKey
|
||||
var pk PublicKey
|
||||
|
||||
if len(seed) != KeySeedSize {
|
||||
panic("seed must be of length KeySeedSize")
|
||||
}
|
||||
|
||||
pk.pk, sk.sk = cpapke.NewKeyFromSeed(seed[:cpapke.KeySeedSize])
|
||||
sk.pk = pk.pk
|
||||
copy(sk.z[:], seed[cpapke.KeySeedSize:])
|
||||
|
||||
// Compute H(pk)
|
||||
var ppk [cpapke.PublicKeySize]byte
|
||||
sk.pk.Pack(ppk[:])
|
||||
h := sha3.New256()
|
||||
h.Write(ppk[:])
|
||||
h.Read(sk.hpk[:])
|
||||
copy(pk.hpk[:], sk.hpk[:])
|
||||
|
||||
return &pk, &sk
|
||||
}
|
||||
|
||||
// GenerateKeyPair generates public and private keys using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) {
|
||||
var seed [KeySeedSize]byte
|
||||
if rand == nil {
|
||||
rand = cryptoRand.Reader
|
||||
}
|
||||
_, err := io.ReadFull(rand, seed[:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk, sk := NewKeyFromSeed(seed[:])
|
||||
return pk, sk, nil
|
||||
}
|
||||
|
||||
// EncapsulateTo generates a shared key and ciphertext that contains it
|
||||
// for the public key using randomness from seed and writes the shared key
|
||||
// to ss and ciphertext to ct.
|
||||
//
|
||||
// Panics if ss, ct or seed are not of length SharedKeySize, CiphertextSize
|
||||
// and EncapsulationSeedSize respectively.
|
||||
//
|
||||
// seed may be nil, in which case crypto/rand.Reader is used to generate one.
|
||||
func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) {
|
||||
if seed == nil {
|
||||
seed = make([]byte, EncapsulationSeedSize)
|
||||
cryptoRand.Read(seed[:])
|
||||
} else {
|
||||
if len(seed) != EncapsulationSeedSize {
|
||||
panic("seed must be of length EncapsulationSeedSize")
|
||||
}
|
||||
}
|
||||
|
||||
if len(ct) != CiphertextSize {
|
||||
panic("ct must be of length CiphertextSize")
|
||||
}
|
||||
|
||||
if len(ss) != SharedKeySize {
|
||||
panic("ss must be of length SharedKeySize")
|
||||
}
|
||||
|
||||
// m = H(seed)
|
||||
var m [32]byte
|
||||
h := sha3.New256()
|
||||
h.Write(seed[:])
|
||||
h.Read(m[:])
|
||||
|
||||
// (K', r) = G(m ‖ H(pk))
|
||||
var kr [64]byte
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(pk.hpk[:])
|
||||
g.Read(kr[:])
|
||||
|
||||
// c = Kyber.CPAPKE.Enc(pk, m, r)
|
||||
pk.pk.EncryptTo(ct, m[:], kr[32:])
|
||||
|
||||
// Compute H(c) and put in second slot of kr, which will be (K', H(c)).
|
||||
h.Reset()
|
||||
h.Write(ct[:CiphertextSize])
|
||||
h.Read(kr[32:])
|
||||
|
||||
// K = KDF(K' ‖ H(c))
|
||||
kdf := sha3.NewShake256()
|
||||
kdf.Write(kr[:])
|
||||
kdf.Read(ss[:SharedKeySize])
|
||||
}
|
||||
|
||||
// DecapsulateTo computes the shared key which is encapsulated in ct
|
||||
// for the private key.
|
||||
//
|
||||
// Panics if ct or ss are not of length CiphertextSize and SharedKeySize
|
||||
// respectively.
|
||||
func (sk *PrivateKey) DecapsulateTo(ss, ct []byte) {
|
||||
if len(ct) != CiphertextSize {
|
||||
panic("ct must be of length CiphertextSize")
|
||||
}
|
||||
|
||||
if len(ss) != SharedKeySize {
|
||||
panic("ss must be of length SharedKeySize")
|
||||
}
|
||||
|
||||
// m' = Kyber.CPAPKE.Dec(sk, ct)
|
||||
var m2 [32]byte
|
||||
sk.sk.DecryptTo(m2[:], ct)
|
||||
|
||||
// (K'', r') = G(m' ‖ H(pk))
|
||||
var kr2 [64]byte
|
||||
g := sha3.New512()
|
||||
g.Write(m2[:])
|
||||
g.Write(sk.hpk[:])
|
||||
g.Read(kr2[:])
|
||||
|
||||
// c' = Kyber.CPAPKE.Enc(pk, m', r')
|
||||
var ct2 [CiphertextSize]byte
|
||||
sk.pk.EncryptTo(ct2[:], m2[:], kr2[32:])
|
||||
|
||||
// Compute H(c) and put in second slot of kr2, which will be (K'', H(c)).
|
||||
h := sha3.New256()
|
||||
h.Write(ct[:CiphertextSize])
|
||||
h.Read(kr2[32:])
|
||||
|
||||
// Replace K'' by z in the first slot of kr2 if c ≠ c'.
|
||||
subtle.ConstantTimeCopy(
|
||||
1-subtle.ConstantTimeCompare(ct, ct2[:]),
|
||||
kr2[:32],
|
||||
sk.z[:],
|
||||
)
|
||||
|
||||
// K = KDF(K''/z, H(c))
|
||||
kdf := sha3.NewShake256()
|
||||
kdf.Write(kr2[:])
|
||||
kdf.Read(ss[:SharedKeySize])
|
||||
}
|
||||
|
||||
// Packs sk to buf.
|
||||
//
|
||||
// Panics if buf is not of size PrivateKeySize.
|
||||
func (sk *PrivateKey) Pack(buf []byte) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
panic("buf must be of length PrivateKeySize")
|
||||
}
|
||||
|
||||
sk.sk.Pack(buf[:cpapke.PrivateKeySize])
|
||||
buf = buf[cpapke.PrivateKeySize:]
|
||||
sk.pk.Pack(buf[:cpapke.PublicKeySize])
|
||||
buf = buf[cpapke.PublicKeySize:]
|
||||
copy(buf, sk.hpk[:])
|
||||
buf = buf[32:]
|
||||
copy(buf, sk.z[:])
|
||||
}
|
||||
|
||||
// Unpacks sk from buf.
|
||||
//
|
||||
// Panics if buf is not of size PrivateKeySize.
|
||||
func (sk *PrivateKey) Unpack(buf []byte) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
panic("buf must be of length PrivateKeySize")
|
||||
}
|
||||
|
||||
sk.sk = new(cpapke.PrivateKey)
|
||||
sk.sk.Unpack(buf[:cpapke.PrivateKeySize])
|
||||
buf = buf[cpapke.PrivateKeySize:]
|
||||
sk.pk = new(cpapke.PublicKey)
|
||||
sk.pk.Unpack(buf[:cpapke.PublicKeySize])
|
||||
buf = buf[cpapke.PublicKeySize:]
|
||||
copy(sk.hpk[:], buf[:32])
|
||||
copy(sk.z[:], buf[32:])
|
||||
}
|
||||
|
||||
// Packs pk to buf.
|
||||
//
|
||||
// Panics if buf is not of size PublicKeySize.
|
||||
func (pk *PublicKey) Pack(buf []byte) {
|
||||
if len(buf) != PublicKeySize {
|
||||
panic("buf must be of length PublicKeySize")
|
||||
}
|
||||
|
||||
pk.pk.Pack(buf)
|
||||
}
|
||||
|
||||
// Unpacks pk from buf.
|
||||
//
|
||||
// Panics if buf is not of size PublicKeySize.
|
||||
func (pk *PublicKey) Unpack(buf []byte) {
|
||||
if len(buf) != PublicKeySize {
|
||||
panic("buf must be of length PublicKeySize")
|
||||
}
|
||||
|
||||
pk.pk = new(cpapke.PublicKey)
|
||||
pk.pk.Unpack(buf)
|
||||
|
||||
// Compute cached H(pk)
|
||||
h := sha3.New256()
|
||||
h.Write(buf)
|
||||
h.Read(pk.hpk[:])
|
||||
}
|
||||
|
||||
// Boilerplate down below for the KEM scheme API.
|
||||
|
||||
type scheme struct{}
|
||||
|
||||
var sch kem.Scheme = &scheme{}
|
||||
|
||||
// Scheme returns a KEM interface.
|
||||
func Scheme() kem.Scheme { return sch }
|
||||
|
||||
func (*scheme) Name() string { return "Kyber1024" }
|
||||
func (*scheme) PublicKeySize() int { return PublicKeySize }
|
||||
func (*scheme) PrivateKeySize() int { return PrivateKeySize }
|
||||
func (*scheme) SeedSize() int { return KeySeedSize }
|
||||
func (*scheme) SharedKeySize() int { return SharedKeySize }
|
||||
func (*scheme) CiphertextSize() int { return CiphertextSize }
|
||||
func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
|
||||
|
||||
func (sk *PrivateKey) Scheme() kem.Scheme { return sch }
|
||||
func (pk *PublicKey) Scheme() kem.Scheme { return sch }
|
||||
|
||||
func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
|
||||
var ret [PrivateKeySize]byte
|
||||
sk.Pack(ret[:])
|
||||
return ret[:], nil
|
||||
}
|
||||
|
||||
func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
|
||||
oth, ok := other.(*PrivateKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if sk.pk == nil && oth.pk == nil {
|
||||
return true
|
||||
}
|
||||
if sk.pk == nil || oth.pk == nil {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(sk.hpk[:], oth.hpk[:]) ||
|
||||
!bytes.Equal(sk.z[:], oth.z[:]) {
|
||||
return false
|
||||
}
|
||||
return sk.sk.Equal(oth.sk)
|
||||
}
|
||||
|
||||
func (pk *PublicKey) Equal(other kem.PublicKey) bool {
|
||||
oth, ok := other.(*PublicKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if pk.pk == nil && oth.pk == nil {
|
||||
return true
|
||||
}
|
||||
if pk.pk == nil || oth.pk == nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(pk.hpk[:], oth.hpk[:])
|
||||
}
|
||||
|
||||
func (sk *PrivateKey) Public() kem.PublicKey {
|
||||
pk := new(PublicKey)
|
||||
pk.pk = sk.pk
|
||||
copy(pk.hpk[:], sk.hpk[:])
|
||||
return pk
|
||||
}
|
||||
|
||||
func (pk *PublicKey) MarshalBinary() ([]byte, error) {
|
||||
var ret [PublicKeySize]byte
|
||||
pk.Pack(ret[:])
|
||||
return ret[:], nil
|
||||
}
|
||||
|
||||
func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
|
||||
return GenerateKeyPair(cryptoRand.Reader)
|
||||
}
|
||||
|
||||
func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
|
||||
if len(seed) != KeySeedSize {
|
||||
panic(kem.ErrSeedSize)
|
||||
}
|
||||
return NewKeyFromSeed(seed[:])
|
||||
}
|
||||
|
||||
func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
|
||||
ct = make([]byte, CiphertextSize)
|
||||
ss = make([]byte, SharedKeySize)
|
||||
|
||||
pub, ok := pk.(*PublicKey)
|
||||
if !ok {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
pub.EncapsulateTo(ct, ss, nil)
|
||||
return
|
||||
}
|
||||
|
||||
func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (
|
||||
ct, ss []byte, err error) {
|
||||
if len(seed) != EncapsulationSeedSize {
|
||||
return nil, nil, kem.ErrSeedSize
|
||||
}
|
||||
|
||||
ct = make([]byte, CiphertextSize)
|
||||
ss = make([]byte, SharedKeySize)
|
||||
|
||||
pub, ok := pk.(*PublicKey)
|
||||
if !ok {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
pub.EncapsulateTo(ct, ss, seed)
|
||||
return
|
||||
}
|
||||
|
||||
func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
|
||||
if len(ct) != CiphertextSize {
|
||||
return nil, kem.ErrCiphertextSize
|
||||
}
|
||||
|
||||
priv, ok := sk.(*PrivateKey)
|
||||
if !ok {
|
||||
return nil, kem.ErrTypeMismatch
|
||||
}
|
||||
ss := make([]byte, SharedKeySize)
|
||||
priv.DecapsulateTo(ss, ct)
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
|
||||
if len(buf) != PublicKeySize {
|
||||
return nil, kem.ErrPubKeySize
|
||||
}
|
||||
var ret PublicKey
|
||||
ret.Unpack(buf)
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
return nil, kem.ErrPrivKeySize
|
||||
}
|
||||
var ret PrivateKey
|
||||
ret.Unpack(buf)
|
||||
return &ret, nil
|
||||
}
|
402
vendor/github.com/cloudflare/circl/kem/kyber/kyber512/kyber.go
generated
vendored
Normal file
402
vendor/github.com/cloudflare/circl/kem/kyber/kyber512/kyber.go
generated
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
// Code generated from pkg.templ.go. DO NOT EDIT.
|
||||
|
||||
// Package kyber512 implements the IND-CCA2 secure key encapsulation mechanism
|
||||
// Kyber512.CCAKEM as submitted to round 3 of the NIST PQC competition and
|
||||
// described in
|
||||
//
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf
|
||||
package kyber512
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/subtle"
|
||||
"io"
|
||||
|
||||
cryptoRand "crypto/rand"
|
||||
"github.com/cloudflare/circl/internal/sha3"
|
||||
"github.com/cloudflare/circl/kem"
|
||||
cpapke "github.com/cloudflare/circl/pke/kyber/kyber512"
|
||||
)
|
||||
|
||||
const (
|
||||
// Size of seed for NewKeyFromSeed
|
||||
KeySeedSize = cpapke.KeySeedSize + 32
|
||||
|
||||
// Size of seed for EncapsulateTo.
|
||||
EncapsulationSeedSize = 32
|
||||
|
||||
// Size of the established shared key.
|
||||
SharedKeySize = 32
|
||||
|
||||
// Size of the encapsulated shared key.
|
||||
CiphertextSize = cpapke.CiphertextSize
|
||||
|
||||
// Size of a packed public key.
|
||||
PublicKeySize = cpapke.PublicKeySize
|
||||
|
||||
// Size of a packed private key.
|
||||
PrivateKeySize = cpapke.PrivateKeySize + cpapke.PublicKeySize + 64
|
||||
)
|
||||
|
||||
// Type of a Kyber512.CCAKEM public key
|
||||
type PublicKey struct {
|
||||
pk *cpapke.PublicKey
|
||||
|
||||
hpk [32]byte // H(pk)
|
||||
}
|
||||
|
||||
// Type of a Kyber512.CCAKEM private key
|
||||
type PrivateKey struct {
|
||||
sk *cpapke.PrivateKey
|
||||
pk *cpapke.PublicKey
|
||||
hpk [32]byte // H(pk)
|
||||
z [32]byte
|
||||
}
|
||||
|
||||
// NewKeyFromSeed derives a public/private keypair deterministically
|
||||
// from the given seed.
|
||||
//
|
||||
// Panics if seed is not of length KeySeedSize.
|
||||
func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) {
|
||||
var sk PrivateKey
|
||||
var pk PublicKey
|
||||
|
||||
if len(seed) != KeySeedSize {
|
||||
panic("seed must be of length KeySeedSize")
|
||||
}
|
||||
|
||||
pk.pk, sk.sk = cpapke.NewKeyFromSeed(seed[:cpapke.KeySeedSize])
|
||||
sk.pk = pk.pk
|
||||
copy(sk.z[:], seed[cpapke.KeySeedSize:])
|
||||
|
||||
// Compute H(pk)
|
||||
var ppk [cpapke.PublicKeySize]byte
|
||||
sk.pk.Pack(ppk[:])
|
||||
h := sha3.New256()
|
||||
h.Write(ppk[:])
|
||||
h.Read(sk.hpk[:])
|
||||
copy(pk.hpk[:], sk.hpk[:])
|
||||
|
||||
return &pk, &sk
|
||||
}
|
||||
|
||||
// GenerateKeyPair generates public and private keys using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) {
|
||||
var seed [KeySeedSize]byte
|
||||
if rand == nil {
|
||||
rand = cryptoRand.Reader
|
||||
}
|
||||
_, err := io.ReadFull(rand, seed[:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk, sk := NewKeyFromSeed(seed[:])
|
||||
return pk, sk, nil
|
||||
}
|
||||
|
||||
// EncapsulateTo generates a shared key and ciphertext that contains it
|
||||
// for the public key using randomness from seed and writes the shared key
|
||||
// to ss and ciphertext to ct.
|
||||
//
|
||||
// Panics if ss, ct or seed are not of length SharedKeySize, CiphertextSize
|
||||
// and EncapsulationSeedSize respectively.
|
||||
//
|
||||
// seed may be nil, in which case crypto/rand.Reader is used to generate one.
|
||||
func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) {
|
||||
if seed == nil {
|
||||
seed = make([]byte, EncapsulationSeedSize)
|
||||
cryptoRand.Read(seed[:])
|
||||
} else {
|
||||
if len(seed) != EncapsulationSeedSize {
|
||||
panic("seed must be of length EncapsulationSeedSize")
|
||||
}
|
||||
}
|
||||
|
||||
if len(ct) != CiphertextSize {
|
||||
panic("ct must be of length CiphertextSize")
|
||||
}
|
||||
|
||||
if len(ss) != SharedKeySize {
|
||||
panic("ss must be of length SharedKeySize")
|
||||
}
|
||||
|
||||
// m = H(seed)
|
||||
var m [32]byte
|
||||
h := sha3.New256()
|
||||
h.Write(seed[:])
|
||||
h.Read(m[:])
|
||||
|
||||
// (K', r) = G(m ‖ H(pk))
|
||||
var kr [64]byte
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(pk.hpk[:])
|
||||
g.Read(kr[:])
|
||||
|
||||
// c = Kyber.CPAPKE.Enc(pk, m, r)
|
||||
pk.pk.EncryptTo(ct, m[:], kr[32:])
|
||||
|
||||
// Compute H(c) and put in second slot of kr, which will be (K', H(c)).
|
||||
h.Reset()
|
||||
h.Write(ct[:CiphertextSize])
|
||||
h.Read(kr[32:])
|
||||
|
||||
// K = KDF(K' ‖ H(c))
|
||||
kdf := sha3.NewShake256()
|
||||
kdf.Write(kr[:])
|
||||
kdf.Read(ss[:SharedKeySize])
|
||||
}
|
||||
|
||||
// DecapsulateTo computes the shared key which is encapsulated in ct
|
||||
// for the private key.
|
||||
//
|
||||
// Panics if ct or ss are not of length CiphertextSize and SharedKeySize
|
||||
// respectively.
|
||||
func (sk *PrivateKey) DecapsulateTo(ss, ct []byte) {
|
||||
if len(ct) != CiphertextSize {
|
||||
panic("ct must be of length CiphertextSize")
|
||||
}
|
||||
|
||||
if len(ss) != SharedKeySize {
|
||||
panic("ss must be of length SharedKeySize")
|
||||
}
|
||||
|
||||
// m' = Kyber.CPAPKE.Dec(sk, ct)
|
||||
var m2 [32]byte
|
||||
sk.sk.DecryptTo(m2[:], ct)
|
||||
|
||||
// (K'', r') = G(m' ‖ H(pk))
|
||||
var kr2 [64]byte
|
||||
g := sha3.New512()
|
||||
g.Write(m2[:])
|
||||
g.Write(sk.hpk[:])
|
||||
g.Read(kr2[:])
|
||||
|
||||
// c' = Kyber.CPAPKE.Enc(pk, m', r')
|
||||
var ct2 [CiphertextSize]byte
|
||||
sk.pk.EncryptTo(ct2[:], m2[:], kr2[32:])
|
||||
|
||||
// Compute H(c) and put in second slot of kr2, which will be (K'', H(c)).
|
||||
h := sha3.New256()
|
||||
h.Write(ct[:CiphertextSize])
|
||||
h.Read(kr2[32:])
|
||||
|
||||
// Replace K'' by z in the first slot of kr2 if c ≠ c'.
|
||||
subtle.ConstantTimeCopy(
|
||||
1-subtle.ConstantTimeCompare(ct, ct2[:]),
|
||||
kr2[:32],
|
||||
sk.z[:],
|
||||
)
|
||||
|
||||
// K = KDF(K''/z, H(c))
|
||||
kdf := sha3.NewShake256()
|
||||
kdf.Write(kr2[:])
|
||||
kdf.Read(ss[:SharedKeySize])
|
||||
}
|
||||
|
||||
// Packs sk to buf.
|
||||
//
|
||||
// Panics if buf is not of size PrivateKeySize.
|
||||
func (sk *PrivateKey) Pack(buf []byte) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
panic("buf must be of length PrivateKeySize")
|
||||
}
|
||||
|
||||
sk.sk.Pack(buf[:cpapke.PrivateKeySize])
|
||||
buf = buf[cpapke.PrivateKeySize:]
|
||||
sk.pk.Pack(buf[:cpapke.PublicKeySize])
|
||||
buf = buf[cpapke.PublicKeySize:]
|
||||
copy(buf, sk.hpk[:])
|
||||
buf = buf[32:]
|
||||
copy(buf, sk.z[:])
|
||||
}
|
||||
|
||||
// Unpacks sk from buf.
|
||||
//
|
||||
// Panics if buf is not of size PrivateKeySize.
|
||||
func (sk *PrivateKey) Unpack(buf []byte) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
panic("buf must be of length PrivateKeySize")
|
||||
}
|
||||
|
||||
sk.sk = new(cpapke.PrivateKey)
|
||||
sk.sk.Unpack(buf[:cpapke.PrivateKeySize])
|
||||
buf = buf[cpapke.PrivateKeySize:]
|
||||
sk.pk = new(cpapke.PublicKey)
|
||||
sk.pk.Unpack(buf[:cpapke.PublicKeySize])
|
||||
buf = buf[cpapke.PublicKeySize:]
|
||||
copy(sk.hpk[:], buf[:32])
|
||||
copy(sk.z[:], buf[32:])
|
||||
}
|
||||
|
||||
// Packs pk to buf.
|
||||
//
|
||||
// Panics if buf is not of size PublicKeySize.
|
||||
func (pk *PublicKey) Pack(buf []byte) {
|
||||
if len(buf) != PublicKeySize {
|
||||
panic("buf must be of length PublicKeySize")
|
||||
}
|
||||
|
||||
pk.pk.Pack(buf)
|
||||
}
|
||||
|
||||
// Unpacks pk from buf.
|
||||
//
|
||||
// Panics if buf is not of size PublicKeySize.
|
||||
func (pk *PublicKey) Unpack(buf []byte) {
|
||||
if len(buf) != PublicKeySize {
|
||||
panic("buf must be of length PublicKeySize")
|
||||
}
|
||||
|
||||
pk.pk = new(cpapke.PublicKey)
|
||||
pk.pk.Unpack(buf)
|
||||
|
||||
// Compute cached H(pk)
|
||||
h := sha3.New256()
|
||||
h.Write(buf)
|
||||
h.Read(pk.hpk[:])
|
||||
}
|
||||
|
||||
// Boilerplate down below for the KEM scheme API.
|
||||
|
||||
type scheme struct{}
|
||||
|
||||
var sch kem.Scheme = &scheme{}
|
||||
|
||||
// Scheme returns a KEM interface.
|
||||
func Scheme() kem.Scheme { return sch }
|
||||
|
||||
func (*scheme) Name() string { return "Kyber512" }
|
||||
func (*scheme) PublicKeySize() int { return PublicKeySize }
|
||||
func (*scheme) PrivateKeySize() int { return PrivateKeySize }
|
||||
func (*scheme) SeedSize() int { return KeySeedSize }
|
||||
func (*scheme) SharedKeySize() int { return SharedKeySize }
|
||||
func (*scheme) CiphertextSize() int { return CiphertextSize }
|
||||
func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
|
||||
|
||||
func (sk *PrivateKey) Scheme() kem.Scheme { return sch }
|
||||
func (pk *PublicKey) Scheme() kem.Scheme { return sch }
|
||||
|
||||
func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
|
||||
var ret [PrivateKeySize]byte
|
||||
sk.Pack(ret[:])
|
||||
return ret[:], nil
|
||||
}
|
||||
|
||||
func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
|
||||
oth, ok := other.(*PrivateKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if sk.pk == nil && oth.pk == nil {
|
||||
return true
|
||||
}
|
||||
if sk.pk == nil || oth.pk == nil {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(sk.hpk[:], oth.hpk[:]) ||
|
||||
!bytes.Equal(sk.z[:], oth.z[:]) {
|
||||
return false
|
||||
}
|
||||
return sk.sk.Equal(oth.sk)
|
||||
}
|
||||
|
||||
func (pk *PublicKey) Equal(other kem.PublicKey) bool {
|
||||
oth, ok := other.(*PublicKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if pk.pk == nil && oth.pk == nil {
|
||||
return true
|
||||
}
|
||||
if pk.pk == nil || oth.pk == nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(pk.hpk[:], oth.hpk[:])
|
||||
}
|
||||
|
||||
func (sk *PrivateKey) Public() kem.PublicKey {
|
||||
pk := new(PublicKey)
|
||||
pk.pk = sk.pk
|
||||
copy(pk.hpk[:], sk.hpk[:])
|
||||
return pk
|
||||
}
|
||||
|
||||
func (pk *PublicKey) MarshalBinary() ([]byte, error) {
|
||||
var ret [PublicKeySize]byte
|
||||
pk.Pack(ret[:])
|
||||
return ret[:], nil
|
||||
}
|
||||
|
||||
func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
|
||||
return GenerateKeyPair(cryptoRand.Reader)
|
||||
}
|
||||
|
||||
func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
|
||||
if len(seed) != KeySeedSize {
|
||||
panic(kem.ErrSeedSize)
|
||||
}
|
||||
return NewKeyFromSeed(seed[:])
|
||||
}
|
||||
|
||||
func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
|
||||
ct = make([]byte, CiphertextSize)
|
||||
ss = make([]byte, SharedKeySize)
|
||||
|
||||
pub, ok := pk.(*PublicKey)
|
||||
if !ok {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
pub.EncapsulateTo(ct, ss, nil)
|
||||
return
|
||||
}
|
||||
|
||||
func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (
|
||||
ct, ss []byte, err error) {
|
||||
if len(seed) != EncapsulationSeedSize {
|
||||
return nil, nil, kem.ErrSeedSize
|
||||
}
|
||||
|
||||
ct = make([]byte, CiphertextSize)
|
||||
ss = make([]byte, SharedKeySize)
|
||||
|
||||
pub, ok := pk.(*PublicKey)
|
||||
if !ok {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
pub.EncapsulateTo(ct, ss, seed)
|
||||
return
|
||||
}
|
||||
|
||||
func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
|
||||
if len(ct) != CiphertextSize {
|
||||
return nil, kem.ErrCiphertextSize
|
||||
}
|
||||
|
||||
priv, ok := sk.(*PrivateKey)
|
||||
if !ok {
|
||||
return nil, kem.ErrTypeMismatch
|
||||
}
|
||||
ss := make([]byte, SharedKeySize)
|
||||
priv.DecapsulateTo(ss, ct)
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
|
||||
if len(buf) != PublicKeySize {
|
||||
return nil, kem.ErrPubKeySize
|
||||
}
|
||||
var ret PublicKey
|
||||
ret.Unpack(buf)
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
return nil, kem.ErrPrivKeySize
|
||||
}
|
||||
var ret PrivateKey
|
||||
ret.Unpack(buf)
|
||||
return &ret, nil
|
||||
}
|
402
vendor/github.com/cloudflare/circl/kem/kyber/kyber768/kyber.go
generated
vendored
Normal file
402
vendor/github.com/cloudflare/circl/kem/kyber/kyber768/kyber.go
generated
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
// Code generated from pkg.templ.go. DO NOT EDIT.
|
||||
|
||||
// Package kyber768 implements the IND-CCA2 secure key encapsulation mechanism
|
||||
// Kyber768.CCAKEM as submitted to round 3 of the NIST PQC competition and
|
||||
// described in
|
||||
//
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf
|
||||
package kyber768
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/subtle"
|
||||
"io"
|
||||
|
||||
cryptoRand "crypto/rand"
|
||||
"github.com/cloudflare/circl/internal/sha3"
|
||||
"github.com/cloudflare/circl/kem"
|
||||
cpapke "github.com/cloudflare/circl/pke/kyber/kyber768"
|
||||
)
|
||||
|
||||
const (
|
||||
// Size of seed for NewKeyFromSeed
|
||||
KeySeedSize = cpapke.KeySeedSize + 32
|
||||
|
||||
// Size of seed for EncapsulateTo.
|
||||
EncapsulationSeedSize = 32
|
||||
|
||||
// Size of the established shared key.
|
||||
SharedKeySize = 32
|
||||
|
||||
// Size of the encapsulated shared key.
|
||||
CiphertextSize = cpapke.CiphertextSize
|
||||
|
||||
// Size of a packed public key.
|
||||
PublicKeySize = cpapke.PublicKeySize
|
||||
|
||||
// Size of a packed private key.
|
||||
PrivateKeySize = cpapke.PrivateKeySize + cpapke.PublicKeySize + 64
|
||||
)
|
||||
|
||||
// Type of a Kyber768.CCAKEM public key
|
||||
type PublicKey struct {
|
||||
pk *cpapke.PublicKey
|
||||
|
||||
hpk [32]byte // H(pk)
|
||||
}
|
||||
|
||||
// Type of a Kyber768.CCAKEM private key
|
||||
type PrivateKey struct {
|
||||
sk *cpapke.PrivateKey
|
||||
pk *cpapke.PublicKey
|
||||
hpk [32]byte // H(pk)
|
||||
z [32]byte
|
||||
}
|
||||
|
||||
// NewKeyFromSeed derives a public/private keypair deterministically
|
||||
// from the given seed.
|
||||
//
|
||||
// Panics if seed is not of length KeySeedSize.
|
||||
func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) {
|
||||
var sk PrivateKey
|
||||
var pk PublicKey
|
||||
|
||||
if len(seed) != KeySeedSize {
|
||||
panic("seed must be of length KeySeedSize")
|
||||
}
|
||||
|
||||
pk.pk, sk.sk = cpapke.NewKeyFromSeed(seed[:cpapke.KeySeedSize])
|
||||
sk.pk = pk.pk
|
||||
copy(sk.z[:], seed[cpapke.KeySeedSize:])
|
||||
|
||||
// Compute H(pk)
|
||||
var ppk [cpapke.PublicKeySize]byte
|
||||
sk.pk.Pack(ppk[:])
|
||||
h := sha3.New256()
|
||||
h.Write(ppk[:])
|
||||
h.Read(sk.hpk[:])
|
||||
copy(pk.hpk[:], sk.hpk[:])
|
||||
|
||||
return &pk, &sk
|
||||
}
|
||||
|
||||
// GenerateKeyPair generates public and private keys using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) {
|
||||
var seed [KeySeedSize]byte
|
||||
if rand == nil {
|
||||
rand = cryptoRand.Reader
|
||||
}
|
||||
_, err := io.ReadFull(rand, seed[:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk, sk := NewKeyFromSeed(seed[:])
|
||||
return pk, sk, nil
|
||||
}
|
||||
|
||||
// EncapsulateTo generates a shared key and ciphertext that contains it
|
||||
// for the public key using randomness from seed and writes the shared key
|
||||
// to ss and ciphertext to ct.
|
||||
//
|
||||
// Panics if ss, ct or seed are not of length SharedKeySize, CiphertextSize
|
||||
// and EncapsulationSeedSize respectively.
|
||||
//
|
||||
// seed may be nil, in which case crypto/rand.Reader is used to generate one.
|
||||
func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) {
|
||||
if seed == nil {
|
||||
seed = make([]byte, EncapsulationSeedSize)
|
||||
cryptoRand.Read(seed[:])
|
||||
} else {
|
||||
if len(seed) != EncapsulationSeedSize {
|
||||
panic("seed must be of length EncapsulationSeedSize")
|
||||
}
|
||||
}
|
||||
|
||||
if len(ct) != CiphertextSize {
|
||||
panic("ct must be of length CiphertextSize")
|
||||
}
|
||||
|
||||
if len(ss) != SharedKeySize {
|
||||
panic("ss must be of length SharedKeySize")
|
||||
}
|
||||
|
||||
// m = H(seed)
|
||||
var m [32]byte
|
||||
h := sha3.New256()
|
||||
h.Write(seed[:])
|
||||
h.Read(m[:])
|
||||
|
||||
// (K', r) = G(m ‖ H(pk))
|
||||
var kr [64]byte
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(pk.hpk[:])
|
||||
g.Read(kr[:])
|
||||
|
||||
// c = Kyber.CPAPKE.Enc(pk, m, r)
|
||||
pk.pk.EncryptTo(ct, m[:], kr[32:])
|
||||
|
||||
// Compute H(c) and put in second slot of kr, which will be (K', H(c)).
|
||||
h.Reset()
|
||||
h.Write(ct[:CiphertextSize])
|
||||
h.Read(kr[32:])
|
||||
|
||||
// K = KDF(K' ‖ H(c))
|
||||
kdf := sha3.NewShake256()
|
||||
kdf.Write(kr[:])
|
||||
kdf.Read(ss[:SharedKeySize])
|
||||
}
|
||||
|
||||
// DecapsulateTo computes the shared key which is encapsulated in ct
|
||||
// for the private key.
|
||||
//
|
||||
// Panics if ct or ss are not of length CiphertextSize and SharedKeySize
|
||||
// respectively.
|
||||
func (sk *PrivateKey) DecapsulateTo(ss, ct []byte) {
|
||||
if len(ct) != CiphertextSize {
|
||||
panic("ct must be of length CiphertextSize")
|
||||
}
|
||||
|
||||
if len(ss) != SharedKeySize {
|
||||
panic("ss must be of length SharedKeySize")
|
||||
}
|
||||
|
||||
// m' = Kyber.CPAPKE.Dec(sk, ct)
|
||||
var m2 [32]byte
|
||||
sk.sk.DecryptTo(m2[:], ct)
|
||||
|
||||
// (K'', r') = G(m' ‖ H(pk))
|
||||
var kr2 [64]byte
|
||||
g := sha3.New512()
|
||||
g.Write(m2[:])
|
||||
g.Write(sk.hpk[:])
|
||||
g.Read(kr2[:])
|
||||
|
||||
// c' = Kyber.CPAPKE.Enc(pk, m', r')
|
||||
var ct2 [CiphertextSize]byte
|
||||
sk.pk.EncryptTo(ct2[:], m2[:], kr2[32:])
|
||||
|
||||
// Compute H(c) and put in second slot of kr2, which will be (K'', H(c)).
|
||||
h := sha3.New256()
|
||||
h.Write(ct[:CiphertextSize])
|
||||
h.Read(kr2[32:])
|
||||
|
||||
// Replace K'' by z in the first slot of kr2 if c ≠ c'.
|
||||
subtle.ConstantTimeCopy(
|
||||
1-subtle.ConstantTimeCompare(ct, ct2[:]),
|
||||
kr2[:32],
|
||||
sk.z[:],
|
||||
)
|
||||
|
||||
// K = KDF(K''/z, H(c))
|
||||
kdf := sha3.NewShake256()
|
||||
kdf.Write(kr2[:])
|
||||
kdf.Read(ss[:SharedKeySize])
|
||||
}
|
||||
|
||||
// Packs sk to buf.
|
||||
//
|
||||
// Panics if buf is not of size PrivateKeySize.
|
||||
func (sk *PrivateKey) Pack(buf []byte) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
panic("buf must be of length PrivateKeySize")
|
||||
}
|
||||
|
||||
sk.sk.Pack(buf[:cpapke.PrivateKeySize])
|
||||
buf = buf[cpapke.PrivateKeySize:]
|
||||
sk.pk.Pack(buf[:cpapke.PublicKeySize])
|
||||
buf = buf[cpapke.PublicKeySize:]
|
||||
copy(buf, sk.hpk[:])
|
||||
buf = buf[32:]
|
||||
copy(buf, sk.z[:])
|
||||
}
|
||||
|
||||
// Unpacks sk from buf.
|
||||
//
|
||||
// Panics if buf is not of size PrivateKeySize.
|
||||
func (sk *PrivateKey) Unpack(buf []byte) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
panic("buf must be of length PrivateKeySize")
|
||||
}
|
||||
|
||||
sk.sk = new(cpapke.PrivateKey)
|
||||
sk.sk.Unpack(buf[:cpapke.PrivateKeySize])
|
||||
buf = buf[cpapke.PrivateKeySize:]
|
||||
sk.pk = new(cpapke.PublicKey)
|
||||
sk.pk.Unpack(buf[:cpapke.PublicKeySize])
|
||||
buf = buf[cpapke.PublicKeySize:]
|
||||
copy(sk.hpk[:], buf[:32])
|
||||
copy(sk.z[:], buf[32:])
|
||||
}
|
||||
|
||||
// Packs pk to buf.
|
||||
//
|
||||
// Panics if buf is not of size PublicKeySize.
|
||||
func (pk *PublicKey) Pack(buf []byte) {
|
||||
if len(buf) != PublicKeySize {
|
||||
panic("buf must be of length PublicKeySize")
|
||||
}
|
||||
|
||||
pk.pk.Pack(buf)
|
||||
}
|
||||
|
||||
// Unpacks pk from buf.
|
||||
//
|
||||
// Panics if buf is not of size PublicKeySize.
|
||||
func (pk *PublicKey) Unpack(buf []byte) {
|
||||
if len(buf) != PublicKeySize {
|
||||
panic("buf must be of length PublicKeySize")
|
||||
}
|
||||
|
||||
pk.pk = new(cpapke.PublicKey)
|
||||
pk.pk.Unpack(buf)
|
||||
|
||||
// Compute cached H(pk)
|
||||
h := sha3.New256()
|
||||
h.Write(buf)
|
||||
h.Read(pk.hpk[:])
|
||||
}
|
||||
|
||||
// Boilerplate down below for the KEM scheme API.
|
||||
|
||||
type scheme struct{}
|
||||
|
||||
var sch kem.Scheme = &scheme{}
|
||||
|
||||
// Scheme returns a KEM interface.
|
||||
func Scheme() kem.Scheme { return sch }
|
||||
|
||||
func (*scheme) Name() string { return "Kyber768" }
|
||||
func (*scheme) PublicKeySize() int { return PublicKeySize }
|
||||
func (*scheme) PrivateKeySize() int { return PrivateKeySize }
|
||||
func (*scheme) SeedSize() int { return KeySeedSize }
|
||||
func (*scheme) SharedKeySize() int { return SharedKeySize }
|
||||
func (*scheme) CiphertextSize() int { return CiphertextSize }
|
||||
func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
|
||||
|
||||
func (sk *PrivateKey) Scheme() kem.Scheme { return sch }
|
||||
func (pk *PublicKey) Scheme() kem.Scheme { return sch }
|
||||
|
||||
func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
|
||||
var ret [PrivateKeySize]byte
|
||||
sk.Pack(ret[:])
|
||||
return ret[:], nil
|
||||
}
|
||||
|
||||
func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
|
||||
oth, ok := other.(*PrivateKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if sk.pk == nil && oth.pk == nil {
|
||||
return true
|
||||
}
|
||||
if sk.pk == nil || oth.pk == nil {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(sk.hpk[:], oth.hpk[:]) ||
|
||||
!bytes.Equal(sk.z[:], oth.z[:]) {
|
||||
return false
|
||||
}
|
||||
return sk.sk.Equal(oth.sk)
|
||||
}
|
||||
|
||||
func (pk *PublicKey) Equal(other kem.PublicKey) bool {
|
||||
oth, ok := other.(*PublicKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if pk.pk == nil && oth.pk == nil {
|
||||
return true
|
||||
}
|
||||
if pk.pk == nil || oth.pk == nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(pk.hpk[:], oth.hpk[:])
|
||||
}
|
||||
|
||||
func (sk *PrivateKey) Public() kem.PublicKey {
|
||||
pk := new(PublicKey)
|
||||
pk.pk = sk.pk
|
||||
copy(pk.hpk[:], sk.hpk[:])
|
||||
return pk
|
||||
}
|
||||
|
||||
func (pk *PublicKey) MarshalBinary() ([]byte, error) {
|
||||
var ret [PublicKeySize]byte
|
||||
pk.Pack(ret[:])
|
||||
return ret[:], nil
|
||||
}
|
||||
|
||||
func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
|
||||
return GenerateKeyPair(cryptoRand.Reader)
|
||||
}
|
||||
|
||||
func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
|
||||
if len(seed) != KeySeedSize {
|
||||
panic(kem.ErrSeedSize)
|
||||
}
|
||||
return NewKeyFromSeed(seed[:])
|
||||
}
|
||||
|
||||
func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
|
||||
ct = make([]byte, CiphertextSize)
|
||||
ss = make([]byte, SharedKeySize)
|
||||
|
||||
pub, ok := pk.(*PublicKey)
|
||||
if !ok {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
pub.EncapsulateTo(ct, ss, nil)
|
||||
return
|
||||
}
|
||||
|
||||
func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (
|
||||
ct, ss []byte, err error) {
|
||||
if len(seed) != EncapsulationSeedSize {
|
||||
return nil, nil, kem.ErrSeedSize
|
||||
}
|
||||
|
||||
ct = make([]byte, CiphertextSize)
|
||||
ss = make([]byte, SharedKeySize)
|
||||
|
||||
pub, ok := pk.(*PublicKey)
|
||||
if !ok {
|
||||
return nil, nil, kem.ErrTypeMismatch
|
||||
}
|
||||
pub.EncapsulateTo(ct, ss, seed)
|
||||
return
|
||||
}
|
||||
|
||||
func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
|
||||
if len(ct) != CiphertextSize {
|
||||
return nil, kem.ErrCiphertextSize
|
||||
}
|
||||
|
||||
priv, ok := sk.(*PrivateKey)
|
||||
if !ok {
|
||||
return nil, kem.ErrTypeMismatch
|
||||
}
|
||||
ss := make([]byte, SharedKeySize)
|
||||
priv.DecapsulateTo(ss, ct)
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
|
||||
if len(buf) != PublicKeySize {
|
||||
return nil, kem.ErrPubKeySize
|
||||
}
|
||||
var ret PublicKey
|
||||
ret.Unpack(buf)
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
|
||||
if len(buf) != PrivateKeySize {
|
||||
return nil, kem.ErrPrivKeySize
|
||||
}
|
||||
var ret PrivateKey
|
||||
ret.Unpack(buf)
|
||||
return &ret, nil
|
||||
}
|
Reference in New Issue
Block a user