scheme.go raw
1 package xwing
2
3 import (
4 "bytes"
5 cryptoRand "crypto/rand"
6 "crypto/subtle"
7
8 "github.com/cloudflare/circl/kem"
9 "github.com/cloudflare/circl/kem/mlkem/mlkem768"
10 )
11
12 // This file contains the boilerplate code to connect X-Wing to the
13 // generic KEM API.
14
15 // Returns the generic KEM interface for X-Wing PQ/T hybrid KEM.
16 func Scheme() kem.Scheme { return scheme{} }
17
18 type scheme struct{}
19
20 func (scheme) Name() string { return "X-Wing" }
21 func (scheme) PublicKeySize() int { return PublicKeySize }
22 func (scheme) PrivateKeySize() int { return PrivateKeySize }
23 func (scheme) SeedSize() int { return SeedSize }
24 func (scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
25 func (scheme) SharedKeySize() int { return SharedKeySize }
26 func (scheme) CiphertextSize() int { return CiphertextSize }
27 func (*PrivateKey) Scheme() kem.Scheme { return scheme{} }
28 func (*PublicKey) Scheme() kem.Scheme { return scheme{} }
29
30 func (sch scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
31 var seed [EncapsulationSeedSize]byte
32 _, err = cryptoRand.Read(seed[:])
33 if err != nil {
34 return
35 }
36 return sch.EncapsulateDeterministically(pk, seed[:])
37 }
38
39 func (scheme) EncapsulateDeterministically(
40 pk kem.PublicKey, seed []byte,
41 ) ([]byte, []byte, error) {
42 if len(seed) != EncapsulationSeedSize {
43 return nil, nil, kem.ErrSeedSize
44 }
45 pub, ok := pk.(*PublicKey)
46 if !ok {
47 return nil, nil, kem.ErrTypeMismatch
48 }
49 var (
50 ct [CiphertextSize]byte
51 ss [SharedKeySize]byte
52 )
53 pub.EncapsulateTo(ct[:], ss[:], seed)
54 return ct[:], ss[:], nil
55 }
56
57 func (scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
58 var pk PublicKey
59 if len(buf) != PublicKeySize {
60 return nil, kem.ErrPubKeySize
61 }
62
63 if err := pk.Unpack(buf); err != nil {
64 return nil, err
65 }
66 return &pk, nil
67 }
68
69 func (scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
70 var sk PrivateKey
71 if len(buf) != PrivateKeySize {
72 return nil, kem.ErrPrivKeySize
73 }
74
75 sk.Unpack(buf)
76 return &sk, nil
77 }
78
79 func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
80 var ret [PrivateKeySize]byte
81 sk.Pack(ret[:])
82 return ret[:], nil
83 }
84
85 func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
86 oth, ok := other.(*PrivateKey)
87 if !ok {
88 return false
89 }
90 return sk.m.Equal(&oth.m) &&
91 subtle.ConstantTimeCompare(oth.x[:], sk.x[:]) == 1
92 }
93
94 func (sk *PrivateKey) Public() kem.PublicKey {
95 var pk PublicKey
96 pk.m = *(sk.m.Public().(*mlkem768.PublicKey))
97 pk.x = sk.xpk
98 return &pk
99 }
100
101 func (pk *PublicKey) Equal(other kem.PublicKey) bool {
102 oth, ok := other.(*PublicKey)
103 if !ok {
104 return false
105 }
106 return pk.m.Equal(&oth.m) && bytes.Equal(pk.x[:], oth.x[:])
107 }
108
109 func (pk *PublicKey) MarshalBinary() ([]byte, error) {
110 var ret [PublicKeySize]byte
111 pk.Pack(ret[:])
112 return ret[:], nil
113 }
114
115 func (scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
116 sk, pk := DeriveKeyPair(seed)
117 return pk, sk
118 }
119
120 func (scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
121 sk, pk, err := GenerateKeyPair(nil)
122 return pk, sk, err
123 }
124
125 func (scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
126 if len(ct) != CiphertextSize {
127 return nil, kem.ErrCiphertextSize
128 }
129
130 var ss [SharedKeySize]byte
131
132 priv, ok := sk.(*PrivateKey)
133 if !ok {
134 return nil, kem.ErrTypeMismatch
135 }
136
137 priv.DecapsulateTo(ss[:], ct[:])
138
139 return ss[:], nil
140 }
141