kyber.go raw
1 // Code generated from pkg.templ.go. DO NOT EDIT.
2
3 // Package kyber768 implements the IND-CCA2 secure key encapsulation mechanism
4 // Kyber768.CCAKEM as submitted to round 3 of the NIST PQC competition and
5 // described in
6 //
7 // https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf
8 package kyber768
9
10 import (
11 "bytes"
12 "crypto/subtle"
13 "io"
14
15 cryptoRand "crypto/rand"
16 "github.com/cloudflare/circl/internal/sha3"
17 "github.com/cloudflare/circl/kem"
18 cpapke "github.com/cloudflare/circl/pke/kyber/kyber768"
19 )
20
21 const (
22 // Size of seed for NewKeyFromSeed
23 KeySeedSize = cpapke.KeySeedSize + 32
24
25 // Size of seed for EncapsulateTo.
26 EncapsulationSeedSize = 32
27
28 // Size of the established shared key.
29 SharedKeySize = 32
30
31 // Size of the encapsulated shared key.
32 CiphertextSize = cpapke.CiphertextSize
33
34 // Size of a packed public key.
35 PublicKeySize = cpapke.PublicKeySize
36
37 // Size of a packed private key.
38 PrivateKeySize = cpapke.PrivateKeySize + cpapke.PublicKeySize + 64
39 )
40
41 // Type of a Kyber768.CCAKEM public key
42 type PublicKey struct {
43 pk *cpapke.PublicKey
44
45 hpk [32]byte // H(pk)
46 }
47
48 // Type of a Kyber768.CCAKEM private key
49 type PrivateKey struct {
50 sk *cpapke.PrivateKey
51 pk *cpapke.PublicKey
52 hpk [32]byte // H(pk)
53 z [32]byte
54 }
55
56 // NewKeyFromSeed derives a public/private keypair deterministically
57 // from the given seed.
58 //
59 // Panics if seed is not of length KeySeedSize.
60 func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) {
61 var sk PrivateKey
62 var pk PublicKey
63
64 if len(seed) != KeySeedSize {
65 panic("seed must be of length KeySeedSize")
66 }
67
68 pk.pk, sk.sk = cpapke.NewKeyFromSeed(seed[:cpapke.KeySeedSize])
69 sk.pk = pk.pk
70 copy(sk.z[:], seed[cpapke.KeySeedSize:])
71
72 // Compute H(pk)
73 var ppk [cpapke.PublicKeySize]byte
74 sk.pk.Pack(ppk[:])
75 h := sha3.New256()
76 h.Write(ppk[:])
77 h.Read(sk.hpk[:])
78 copy(pk.hpk[:], sk.hpk[:])
79
80 return &pk, &sk
81 }
82
83 // GenerateKeyPair generates public and private keys using entropy from rand.
84 // If rand is nil, crypto/rand.Reader will be used.
85 func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) {
86 var seed [KeySeedSize]byte
87 if rand == nil {
88 rand = cryptoRand.Reader
89 }
90 _, err := io.ReadFull(rand, seed[:])
91 if err != nil {
92 return nil, nil, err
93 }
94 pk, sk := NewKeyFromSeed(seed[:])
95 return pk, sk, nil
96 }
97
98 // EncapsulateTo generates a shared key and ciphertext that contains it
99 // for the public key using randomness from seed and writes the shared key
100 // to ss and ciphertext to ct.
101 //
102 // Panics if ss, ct or seed are not of length SharedKeySize, CiphertextSize
103 // and EncapsulationSeedSize respectively.
104 //
105 // seed may be nil, in which case crypto/rand.Reader is used to generate one.
106 func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) {
107 if seed == nil {
108 seed = make([]byte, EncapsulationSeedSize)
109 if _, err := cryptoRand.Read(seed[:]); err != nil {
110 panic(err)
111 }
112 } else {
113 if len(seed) != EncapsulationSeedSize {
114 panic("seed must be of length EncapsulationSeedSize")
115 }
116 }
117
118 if len(ct) != CiphertextSize {
119 panic("ct must be of length CiphertextSize")
120 }
121
122 if len(ss) != SharedKeySize {
123 panic("ss must be of length SharedKeySize")
124 }
125
126 var m [32]byte
127 // m = H(seed), the hash of shame
128 h := sha3.New256()
129 h.Write(seed)
130 h.Read(m[:])
131
132 // (K', r) = G(m ‖ H(pk))
133 var kr [64]byte
134 g := sha3.New512()
135 g.Write(m[:])
136 g.Write(pk.hpk[:])
137 g.Read(kr[:])
138
139 // c = Kyber.CPAPKE.Enc(pk, m, r)
140 pk.pk.EncryptTo(ct, m[:], kr[32:])
141
142 // Compute H(c) and put in second slot of kr, which will be (K', H(c)).
143 h.Reset()
144 h.Write(ct[:CiphertextSize])
145 h.Read(kr[32:])
146
147 // K = KDF(K' ‖ H(c))
148 kdf := sha3.NewShake256()
149 kdf.Write(kr[:])
150 kdf.Read(ss[:SharedKeySize])
151 }
152
153 // DecapsulateTo computes the shared key which is encapsulated in ct
154 // for the private key.
155 //
156 // Panics if ct or ss are not of length CiphertextSize and SharedKeySize
157 // respectively.
158 func (sk *PrivateKey) DecapsulateTo(ss, ct []byte) {
159 if len(ct) != CiphertextSize {
160 panic("ct must be of length CiphertextSize")
161 }
162
163 if len(ss) != SharedKeySize {
164 panic("ss must be of length SharedKeySize")
165 }
166
167 // m' = Kyber.CPAPKE.Dec(sk, ct)
168 var m2 [32]byte
169 sk.sk.DecryptTo(m2[:], ct)
170
171 // (K'', r') = G(m' ‖ H(pk))
172 var kr2 [64]byte
173 g := sha3.New512()
174 g.Write(m2[:])
175 g.Write(sk.hpk[:])
176 g.Read(kr2[:])
177
178 // c' = Kyber.CPAPKE.Enc(pk, m', r')
179 var ct2 [CiphertextSize]byte
180 sk.pk.EncryptTo(ct2[:], m2[:], kr2[32:])
181
182 // Compute H(c) and put in second slot of kr2, which will be (K'', H(c)).
183 h := sha3.New256()
184 h.Write(ct[:CiphertextSize])
185 h.Read(kr2[32:])
186
187 // Replace K'' by z in the first slot of kr2 if c ≠ c'.
188 subtle.ConstantTimeCopy(
189 1-subtle.ConstantTimeCompare(ct, ct2[:]),
190 kr2[:32],
191 sk.z[:],
192 )
193
194 // K = KDF(K''/z, H(c))
195 kdf := sha3.NewShake256()
196 kdf.Write(kr2[:])
197 kdf.Read(ss)
198 }
199
200 // Packs sk to buf.
201 //
202 // Panics if buf is not of size PrivateKeySize.
203 func (sk *PrivateKey) Pack(buf []byte) {
204 if len(buf) != PrivateKeySize {
205 panic("buf must be of length PrivateKeySize")
206 }
207
208 sk.sk.Pack(buf[:cpapke.PrivateKeySize])
209 buf = buf[cpapke.PrivateKeySize:]
210 sk.pk.Pack(buf[:cpapke.PublicKeySize])
211 buf = buf[cpapke.PublicKeySize:]
212 copy(buf, sk.hpk[:])
213 buf = buf[32:]
214 copy(buf, sk.z[:])
215 }
216
217 // Unpacks sk from buf.
218 //
219 // Panics if buf is not of size PrivateKeySize.
220 func (sk *PrivateKey) Unpack(buf []byte) {
221 if len(buf) != PrivateKeySize {
222 panic("buf must be of length PrivateKeySize")
223 }
224
225 sk.sk = new(cpapke.PrivateKey)
226 sk.sk.Unpack(buf[:cpapke.PrivateKeySize])
227 buf = buf[cpapke.PrivateKeySize:]
228 sk.pk = new(cpapke.PublicKey)
229 sk.pk.Unpack(buf[:cpapke.PublicKeySize])
230 buf = buf[cpapke.PublicKeySize:]
231 copy(sk.hpk[:], buf[:32])
232 copy(sk.z[:], buf[32:])
233 }
234
235 // Packs pk to buf.
236 //
237 // Panics if buf is not of size PublicKeySize.
238 func (pk *PublicKey) Pack(buf []byte) {
239 if len(buf) != PublicKeySize {
240 panic("buf must be of length PublicKeySize")
241 }
242
243 pk.pk.Pack(buf)
244 }
245
246 // Unpacks pk from buf.
247 //
248 // Panics if buf is not of size PublicKeySize.
249 func (pk *PublicKey) Unpack(buf []byte) {
250 if len(buf) != PublicKeySize {
251 panic("buf must be of length PublicKeySize")
252 }
253
254 pk.pk = new(cpapke.PublicKey)
255 pk.pk.Unpack(buf)
256
257 // Compute cached H(pk)
258 h := sha3.New256()
259 h.Write(buf)
260 h.Read(pk.hpk[:])
261
262 }
263
264 // Boilerplate down below for the KEM scheme API.
265
266 type scheme struct{}
267
268 var sch kem.Scheme = &scheme{}
269
270 // Scheme returns a KEM interface.
271 func Scheme() kem.Scheme { return sch }
272
273 func (*scheme) Name() string { return "Kyber768" }
274 func (*scheme) PublicKeySize() int { return PublicKeySize }
275 func (*scheme) PrivateKeySize() int { return PrivateKeySize }
276 func (*scheme) SeedSize() int { return KeySeedSize }
277 func (*scheme) SharedKeySize() int { return SharedKeySize }
278 func (*scheme) CiphertextSize() int { return CiphertextSize }
279 func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
280
281 func (sk *PrivateKey) Scheme() kem.Scheme { return sch }
282 func (pk *PublicKey) Scheme() kem.Scheme { return sch }
283
284 func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
285 var ret [PrivateKeySize]byte
286 sk.Pack(ret[:])
287 return ret[:], nil
288 }
289
290 func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
291 oth, ok := other.(*PrivateKey)
292 if !ok {
293 return false
294 }
295 if sk.pk == nil && oth.pk == nil {
296 return true
297 }
298 if sk.pk == nil || oth.pk == nil {
299 return false
300 }
301 if !bytes.Equal(sk.hpk[:], oth.hpk[:]) ||
302 subtle.ConstantTimeCompare(sk.z[:], oth.z[:]) != 1 {
303 return false
304 }
305 return sk.sk.Equal(oth.sk)
306 }
307
308 func (pk *PublicKey) Equal(other kem.PublicKey) bool {
309 oth, ok := other.(*PublicKey)
310 if !ok {
311 return false
312 }
313 if pk.pk == nil && oth.pk == nil {
314 return true
315 }
316 if pk.pk == nil || oth.pk == nil {
317 return false
318 }
319 return bytes.Equal(pk.hpk[:], oth.hpk[:])
320 }
321
322 func (sk *PrivateKey) Public() kem.PublicKey {
323 pk := new(PublicKey)
324 pk.pk = sk.pk
325 copy(pk.hpk[:], sk.hpk[:])
326 return pk
327 }
328
329 func (pk *PublicKey) MarshalBinary() ([]byte, error) {
330 var ret [PublicKeySize]byte
331 pk.Pack(ret[:])
332 return ret[:], nil
333 }
334
335 func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
336 return GenerateKeyPair(cryptoRand.Reader)
337 }
338
339 func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
340 if len(seed) != KeySeedSize {
341 panic(kem.ErrSeedSize)
342 }
343 return NewKeyFromSeed(seed[:])
344 }
345
346 func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
347 ct = make([]byte, CiphertextSize)
348 ss = make([]byte, SharedKeySize)
349
350 pub, ok := pk.(*PublicKey)
351 if !ok {
352 return nil, nil, kem.ErrTypeMismatch
353 }
354 pub.EncapsulateTo(ct, ss, nil)
355 return
356 }
357
358 func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (
359 ct, ss []byte, err error) {
360 if len(seed) != EncapsulationSeedSize {
361 return nil, nil, kem.ErrSeedSize
362 }
363
364 ct = make([]byte, CiphertextSize)
365 ss = make([]byte, SharedKeySize)
366
367 pub, ok := pk.(*PublicKey)
368 if !ok {
369 return nil, nil, kem.ErrTypeMismatch
370 }
371 pub.EncapsulateTo(ct, ss, seed)
372 return
373 }
374
375 func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
376 if len(ct) != CiphertextSize {
377 return nil, kem.ErrCiphertextSize
378 }
379
380 priv, ok := sk.(*PrivateKey)
381 if !ok {
382 return nil, kem.ErrTypeMismatch
383 }
384 ss := make([]byte, SharedKeySize)
385 priv.DecapsulateTo(ss, ct)
386 return ss, nil
387 }
388
389 func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
390 var ret PublicKey
391 if len(buf) != PublicKeySize {
392 return nil, kem.ErrPubKeySize
393 }
394 ret.Unpack(buf)
395 return &ret, nil
396 }
397
398 func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
399 if len(buf) != PrivateKeySize {
400 return nil, kem.ErrPrivKeySize
401 }
402 var ret PrivateKey
403 ret.Unpack(buf)
404 return &ret, nil
405 }
406