Skip to content

Commit

Permalink
[WIP] X-Wing PQ/T hybrid
Browse files Browse the repository at this point in the history
  • Loading branch information
bwesterb committed Jan 5, 2024
1 parent 0edf39b commit 99b0e19
Show file tree
Hide file tree
Showing 5 changed files with 515 additions and 0 deletions.
2 changes: 2 additions & 0 deletions kem/schemes/schemes.go
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/cloudflare/circl/kem/mlkem/mlkem1024"
"github.com/cloudflare/circl/kem/mlkem/mlkem512"
"github.com/cloudflare/circl/kem/mlkem/mlkem768"
"github.com/cloudflare/circl/kem/xwing"
)

var allSchemes = [...]kem.Scheme{
Expand All @@ -49,6 +50,7 @@ var allSchemes = [...]kem.Scheme{
hybrid.Kyber768X448(),
hybrid.Kyber1024X448(),
hybrid.P256Kyber768Draft00(),
xwing.Scheme(),
}

var allSchemeNames map[string]kem.Scheme
Expand Down
1 change: 1 addition & 0 deletions kem/schemes/schemes_test.go
Expand Up @@ -163,4 +163,5 @@ func Example_schemes() {
// Kyber768-X448
// Kyber1024-X448
// P256Kyber768Draft00
// X-Wing
}
140 changes: 140 additions & 0 deletions kem/xwing/scheme.go
@@ -0,0 +1,140 @@
package xwing

import (
"bytes"
cryptoRand "crypto/rand"
"crypto/subtle"

"github.com/cloudflare/circl/kem"
"github.com/cloudflare/circl/kem/mlkem/mlkem768"
)

// This file contains the boilerplate code to connect X-Wing to the
// generic KEM API.

// Returns the generic KEM interface for X-Wing PQ/T hybrid KEM.
func Scheme() kem.Scheme { return &xwing }

type scheme struct{}

var xwing scheme

func (*scheme) Name() string { return "X-Wing" }
func (*scheme) PublicKeySize() int { return PublicKeySize }
func (*scheme) PrivateKeySize() int { return PrivateKeySize }
func (*scheme) SeedSize() int { return SeedSize }
func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
func (*scheme) SharedKeySize() int { return SharedKeySize }
func (*scheme) CiphertextSize() int { return CiphertextSize }
func (*PrivateKey) Scheme() kem.Scheme { return &xwing }
func (*PublicKey) Scheme() kem.Scheme { return &xwing }

func (sch *scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
var seed [EncapsulationSeedSize]byte
_, err = cryptoRand.Read(seed[:])
if err != nil {
return
}
return sch.EncapsulateDeterministically(pk, seed[:])
}

func (sch *scheme) EncapsulateDeterministically(
pk kem.PublicKey, seed []byte,
) ([]byte, []byte, error) {
if len(seed) != EncapsulationSeedSize {
return nil, nil, kem.ErrSeedSize
}
pub, ok := pk.(*PublicKey)
if !ok {
return nil, nil, kem.ErrTypeMismatch
}
var (
ct [CiphertextSize]byte
ss [SharedKeySize]byte
)
pub.EncapsulateTo(ct[:], ss[:], seed)
return ct[:], ss[:], nil
}

func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
var pk PublicKey
if len(buf) != PublicKeySize {
return nil, kem.ErrPubKeySize
}

pk.Unpack(buf)
return &pk, nil
}

func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
var sk PrivateKey
if len(buf) != PrivateKeySize {
return nil, kem.ErrPrivKeySize
}

sk.Unpack(buf)
return &sk, nil
}

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
}
return sk.m.Equal(&oth.m) &&
subtle.ConstantTimeCompare(oth.x[:], sk.x[:]) == 1
}

func (sk *PrivateKey) Public() kem.PublicKey {
var pk PublicKey
pk.m = *(sk.m.Public().(*mlkem768.PublicKey))
pk.x = sk.xpk
return &pk
}

func (pk *PublicKey) Equal(other kem.PublicKey) bool {
oth, ok := other.(*PublicKey)
if !ok {
return false
}
return pk.m.Equal(&oth.m) && bytes.Equal(pk.x[:], oth.x[:])
}

func (pk *PublicKey) MarshalBinary() ([]byte, error) {
var ret [PublicKeySize]byte
pk.Pack(ret[:])
return ret[:], nil
}

func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
sk, pk := DeriveKeyPair(seed)
return pk, sk
}

func (sch *scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
sk, pk, err := GenerateKeyPair(nil)
return pk, sk, err
}

func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
if len(ct) != CiphertextSize {
return nil, kem.ErrCiphertextSize
}

var ss [SharedKeySize]byte

priv, ok := sk.(*PrivateKey)
if !ok {
return nil, kem.ErrTypeMismatch
}

priv.DecapsulateTo(ss[:], ct[:])

return ss[:], nil
}

0 comments on commit 99b0e19

Please sign in to comment.