Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Kyber #60

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 162 additions & 12 deletions crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import (

"github.com/cloudflare/circl/dh/sidh"
"github.com/cloudflare/circl/dh/x448"
"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"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519"
)
Expand Down Expand Up @@ -738,6 +742,140 @@ func (s sikeScheme) setEphemeralKeyPair(skE KEMPrivateKey) {
panic("SIKE cannot use a pre-set ephemeral key pair")
}

////////
// Kyber

type kyberPublicKey = kem.PublicKey

type kyberPrivateKey struct {
priv kem.PrivateKey
}

func (priv kyberPrivateKey) PublicKey() KEMPublicKey {
return priv.priv.Public()
}

type kyberScheme struct {
scheme kem.Scheme
id KEMID
newKeyFromSeed func(ikm []byte) (KEMPrivateKey, KEMPublicKey, error)
}

func (s kyberScheme) ID() KEMID {
return s.id
}

func (s kyberScheme) generateKeyPair(rand io.Reader) (KEMPrivateKey, KEMPublicKey, error) {
pub, priv, err := s.scheme.GenerateKeyPair()
if err != nil {
return nil, nil, err
}

return &kyberPrivateKey{priv}, pub, nil
}

func (s kyberScheme) DeriveKeyPair(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
return s.newKeyFromSeed(ikm)
}

func (s kyberScheme) SerializePublicKey(pk KEMPublicKey) []byte {
if pk == nil {
return nil
}

out, err := pk.(kyberPublicKey).MarshalBinary()
if err != nil {
panic(err)
}

return out
}

func (s kyberScheme) SerializePrivateKey(sk KEMPrivateKey) []byte {
if sk == nil {
return nil
}

out, err := sk.(*kyberPrivateKey).priv.MarshalBinary()
if err != nil {
panic(err)
}

return out
}

func (s kyberScheme) DeserializePublicKey(enc []byte) (KEMPublicKey, error) {
return s.scheme.UnmarshalBinaryPublicKey(enc)
}

func (s kyberScheme) DeserializePrivateKey(enc []byte) (KEMPrivateKey, error) {
priv, err := s.scheme.UnmarshalBinaryPrivateKey(enc)
if err != nil {
return nil, err
}

return &kyberPrivateKey{priv}, nil
}

func (s kyberScheme) Encap(rand io.Reader, pkR KEMPublicKey) ([]byte, []byte, error) {
raw := pkR.(kyberPublicKey)
ct, ss, err := s.scheme.Encapsulate(raw)
return ss, ct, err
}

func (s kyberScheme) Decap(enc []byte, skR KEMPrivateKey) ([]byte, error) {
raw := skR.(*kyberPrivateKey).priv
return s.scheme.Decapsulate(raw, enc)
}

func (s kyberScheme) PublicKeySize() int {
return s.scheme.PublicKeySize()
}

func (s kyberScheme) PrivateKeySize() int {
return s.scheme.PrivateKeySize()
}

func (s kyberScheme) setEphemeralKeyPair(skE KEMPrivateKey) {
panic("Kyber cannot use a pre-set ephemeral key pair")
}

func newKyber512Scheme() *kyberScheme {
return &kyberScheme{
scheme: kyber512.Scheme(),
id: KEM_KYBER512,
newKeyFromSeed: func(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
ikm = ikm[:kyber512.KeySeedSize]
pub, priv := kyber512.NewKeyFromSeed(ikm)
return &kyberPrivateKey{priv}, pub, nil
},
}
}

func newKyber768Scheme() *kyberScheme {
return &kyberScheme{
scheme: kyber768.Scheme(),
id: KEM_KYBER768,
newKeyFromSeed: func(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
ikm = ikm[:kyber768.KeySeedSize]
pub, priv := kyber768.NewKeyFromSeed(ikm)
return &kyberPrivateKey{priv}, pub, nil
},
}
}

func newKyber1024Scheme() *kyberScheme {
return &kyberScheme{
scheme: kyber1024.Scheme(),
id: KEM_KYBER1024,
newKeyFromSeed: func(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
ikm = ikm[:kyber1024.KeySeedSize]
pub, priv := kyber1024.NewKeyFromSeed(ikm)
return &kyberPrivateKey{priv}, pub, nil
},
}
}

//////////
// AES-GCM

Expand Down Expand Up @@ -909,21 +1047,27 @@ func (s hkdfScheme) OutputSize() int {
type KEMID uint16

const (
DHKEM_P256 KEMID = 0x0010
DHKEM_P521 KEMID = 0x0012
DHKEM_X25519 KEMID = 0x0020
DHKEM_X448 KEMID = 0x0021
KEM_SIKE503 KEMID = 0xFFFE
KEM_SIKE751 KEMID = 0xFFFF
DHKEM_P256 KEMID = 0x0010
DHKEM_P521 KEMID = 0x0012
DHKEM_X25519 KEMID = 0x0020
DHKEM_X448 KEMID = 0x0021
KEM_KYBER512 KEMID = 0xFFFB
KEM_KYBER768 KEMID = 0xFFFC
KEM_KYBER1024 KEMID = 0xFFFD
KEM_SIKE503 KEMID = 0xFFFE
KEM_SIKE751 KEMID = 0xFFFF
)

var kems = map[KEMID]KEMScheme{
DHKEM_X25519: &dhkemScheme{group: x25519Scheme{}},
DHKEM_X448: &dhkemScheme{group: x448Scheme{}},
DHKEM_P256: &dhkemScheme{group: ecdhScheme{curve: elliptic.P256(), KDF: hkdfScheme{hash: crypto.SHA256}}},
DHKEM_P521: &dhkemScheme{group: ecdhScheme{curve: elliptic.P521(), KDF: hkdfScheme{hash: crypto.SHA512}}},
KEM_SIKE503: &sikeScheme{field: sidh.Fp503, KDF: hkdfScheme{hash: crypto.SHA512}},
KEM_SIKE751: &sikeScheme{field: sidh.Fp751, KDF: hkdfScheme{hash: crypto.SHA512}},
DHKEM_X25519: &dhkemScheme{group: x25519Scheme{}},
DHKEM_X448: &dhkemScheme{group: x448Scheme{}},
DHKEM_P256: &dhkemScheme{group: ecdhScheme{curve: elliptic.P256(), KDF: hkdfScheme{hash: crypto.SHA256}}},
DHKEM_P521: &dhkemScheme{group: ecdhScheme{curve: elliptic.P521(), KDF: hkdfScheme{hash: crypto.SHA512}}},
KEM_KYBER512: newKyber512Scheme(),
KEM_KYBER768: newKyber768Scheme(),
KEM_KYBER1024: newKyber1024Scheme(),
KEM_SIKE503: &sikeScheme{field: sidh.Fp503, KDF: hkdfScheme{hash: crypto.SHA512}},
KEM_SIKE751: &sikeScheme{field: sidh.Fp751, KDF: hkdfScheme{hash: crypto.SHA512}},
}

func newKEMScheme(kemID KEMID) (KEMScheme, bool) {
Expand All @@ -936,6 +1080,12 @@ func newKEMScheme(kemID KEMID) (KEMScheme, bool) {
return &dhkemScheme{group: ecdhScheme{curve: elliptic.P256(), KDF: hkdfScheme{hash: crypto.SHA256}}}, true
case DHKEM_P521:
return &dhkemScheme{group: ecdhScheme{curve: elliptic.P521(), KDF: hkdfScheme{hash: crypto.SHA512}}}, true
case KEM_KYBER512:
return newKyber512Scheme(), true
case KEM_KYBER768:
return newKyber768Scheme(), true
case KEM_KYBER1024:
return newKyber1024Scheme(), true
case KEM_SIKE503:
return &sikeScheme{field: sidh.Fp503, KDF: hkdfScheme{hash: crypto.SHA512}}, true
case KEM_SIKE751:
Expand Down
3 changes: 3 additions & 0 deletions crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ func TestKEMSchemes(t *testing.T) {
&dhkemScheme{group: x448Scheme{}},
&dhkemScheme{group: ecdhScheme{curve: elliptic.P256(), KDF: hkdfScheme{hash: crypto.SHA256}}},
&dhkemScheme{group: ecdhScheme{curve: elliptic.P521(), KDF: hkdfScheme{hash: crypto.SHA256}}},
newKyber512Scheme(),
newKyber768Scheme(),
newKyber1024Scheme(),
&sikeScheme{field: sidh.Fp503, KDF: hkdfScheme{hash: crypto.SHA512}},
&sikeScheme{field: sidh.Fp751, KDF: hkdfScheme{hash: crypto.SHA512}},
}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.14

require (
github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b
github.com/cloudflare/circl v1.0.0
github.com/cloudflare/circl v1.2.0
github.com/stretchr/testify v1.6.1
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
)
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
github.com/bwesterb/go-ristretto v1.2.1 h1:Xd9ZXmjKE2aY8Ub7+4bX7tXsIPsV1pIZaUlJUjI1toE=
github.com/bwesterb/go-ristretto v1.2.1/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b h1:Ves2turKTX7zruivAcUOQg155xggcbv3suVdbKCBQNM=
github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b/go.mod h1:0AZAV7lYvynZQ5ErHlGMKH+4QYMyNCFd+AiL9MlrCYA=
github.com/cloudflare/circl v1.0.0 h1:64b6pyfCFbYm623ncIkYGNZaOcmIbyd+CjyMi2L9vdI=
github.com/cloudflare/circl v1.0.0/go.mod h1:MhjB3NEEhJbTOdLLq964NIUisXDxaE1WkQPUxtgZXiY=
github.com/cloudflare/circl v1.2.0 h1:NheeISPSUcYftKlfrLuOo4T62FkmD4t4jviLfFFYaec=
github.com/cloudflare/circl v1.2.0/go.mod h1:Ch2UgYr6ti2KTtlejELlROl0YIYj7SLjAC8M+INXlMk=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -12,12 +16,23 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed h1:uPxWBzB3+mlnjy9W58qY1j/cjyFjutgw/Vhan2zLy/A=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
Expand Down