1
2 package frodo640shake
3
4 import (
5 "bytes"
6 cryptoRand "crypto/rand"
7 "crypto/subtle"
8 "io"
9
10 "github.com/cloudflare/circl/internal/sha3"
11 "github.com/cloudflare/circl/kem"
12 )
13
14 const (
15 paramN = 640
16
17
18 paramNbar = 8
19
20 logQ = 15
21 logQMask = ((1 << logQ) - 1)
22 seedASize = 16
23 pkHashSize = 16
24
25
26 extractedBits = 2
27
28 messageSize = 16
29 matrixBpPackedSize = (logQ * (paramN * paramNbar)) / 8
30 )
31
32 const (
33
34
35 KeySeedSize = SharedKeySize + SharedKeySize + 16
36
37
38 EncapsulationSeedSize = 16
39
40
41 SharedKeySize = 16
42
43
44 CiphertextSize = 9720
45
46
47 PublicKeySize = 9616
48
49
50 PrivateKeySize = 19888
51 )
52
53
54
55 type (
56 nByNU16 [paramN * paramN]uint16
57 nByNbarU16 [paramN * paramNbar]uint16
58 nbarByNU16 [paramNbar * paramN]uint16
59 nbarByNbarU16 [paramNbar * paramNbar]uint16
60 )
61
62
63 type PublicKey struct {
64 seedA [seedASize]byte
65 matrixB nByNbarU16
66 }
67
68
69 type PrivateKey struct {
70 hashInputIfDecapsFail [SharedKeySize]byte
71 pk *PublicKey
72
73
74 matrixS nByNbarU16
75
76
77 hpk [pkHashSize]byte
78 }
79
80
81
82
83
84 func newKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) {
85 if len(seed) != KeySeedSize {
86 panic("seed must be of length KeySeedSize")
87 }
88
89 var sk PrivateKey
90 var pk PublicKey
91
92 var E nByNbarU16
93 var byteSE [2 * (len(sk.matrixS) + len(E))]byte
94
95 var A nByNU16
96
97
98 shake128 := sha3.NewShake128()
99 _, _ = shake128.Write(seed[2*SharedKeySize:])
100 _, _ = shake128.Read(pk.seedA[:])
101
102 shake128.Reset()
103 _, _ = shake128.Write([]byte{0x5F})
104 _, _ = shake128.Write(seed[SharedKeySize : 2*SharedKeySize])
105 _, _ = shake128.Read(byteSE[:])
106
107 i := 0
108 for i < len(sk.matrixS) {
109 sk.matrixS[i] = uint16(byteSE[i*2]) | (uint16(byteSE[(i*2)+1]) << 8)
110 i++
111 }
112 sample(sk.matrixS[:])
113
114 for j := range E {
115 E[j] = uint16(byteSE[i*2]) | (uint16(byteSE[(i*2)+1]) << 8)
116 i++
117 }
118 sample(E[:])
119
120 expandSeedIntoA(&A, &pk.seedA, &shake128)
121 mulAddASPlusE(&pk.matrixB, &A, &sk.matrixS, &E)
122
123
124 copy(sk.hashInputIfDecapsFail[:], seed[0:SharedKeySize])
125 sk.pk = &pk
126
127
128 shake128.Reset()
129 var ppk [PublicKeySize]byte
130 pk.Pack(ppk[:])
131 _, _ = shake128.Write(ppk[:])
132 _, _ = shake128.Read(sk.hpk[:])
133
134 return &pk, &sk
135 }
136
137
138
139 func generateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) {
140 var seed [KeySeedSize]byte
141 if rand == nil {
142 rand = cryptoRand.Reader
143 }
144 _, err := io.ReadFull(rand, seed[:])
145 if err != nil {
146 return nil, nil, err
147 }
148 pk, sk := newKeyFromSeed(seed[:])
149 return pk, sk, err
150 }
151
152
153
154
155
156
157
158
159
160 func (pk *PublicKey) EncapsulateTo(ct []byte, ss []byte, seed []byte) {
161 if seed == nil {
162 seed = make([]byte, EncapsulationSeedSize)
163 if _, err := cryptoRand.Read(seed[:]); err != nil {
164 panic(err)
165 }
166 }
167 if len(seed) != EncapsulationSeedSize {
168 panic("seed must be of length EncapsulationSeedSize")
169 }
170 if len(ct) != CiphertextSize {
171 panic("ct must be of length CiphertextSize")
172 }
173 if len(ss) != SharedKeySize {
174 panic("ss must be of length SharedKeySize")
175 }
176
177 var G2out [2 * SharedKeySize]byte
178
179 var SpEpEpp [(paramN * paramNbar) + (paramN * paramNbar) + (paramNbar * paramNbar)]uint16
180 var byteSpEpEpp [2 * len(SpEpEpp)]byte
181 Sp := SpEpEpp[:paramN*paramNbar]
182 Ep := SpEpEpp[paramN*paramNbar : 2*paramN*paramNbar]
183 Epp := SpEpEpp[2*paramN*paramNbar:]
184
185 var Bp nbarByNU16
186
187 var V nbarByNbarU16
188 var C nbarByNbarU16
189
190 var A nByNU16
191
192 var hpk [pkHashSize]byte
193
194 var mu [messageSize]byte
195 copy(mu[:], seed[:messageSize])
196
197
198 shake128 := sha3.NewShake128()
199 var ppk [PublicKeySize]byte
200 pk.Pack(ppk[:])
201 _, _ = shake128.Write(ppk[:])
202 _, _ = shake128.Read(hpk[:])
203
204
205 shake128.Reset()
206 _, _ = shake128.Write(hpk[:])
207 _, _ = shake128.Write(mu[:])
208 _, _ = shake128.Read(G2out[:])
209
210
211
212
213 shake128.Reset()
214 _, _ = shake128.Write([]byte{0x96})
215 _, _ = shake128.Write(G2out[:SharedKeySize])
216 _, _ = shake128.Read(byteSpEpEpp[:])
217 for i := range SpEpEpp {
218 SpEpEpp[i] = uint16(byteSpEpEpp[i*2]) | (uint16(byteSpEpEpp[(i*2)+1]) << 8)
219 }
220 sample(SpEpEpp[:])
221
222 expandSeedIntoA(&A, &pk.seedA, &shake128)
223 mulAddSAPlusE(&Bp, Sp, &A, Ep)
224
225 mulAddSBPlusE(&V, Sp, &pk.matrixB, Epp)
226
227
228 encodeMessage(&C, &mu)
229 add(&C, &V, &C)
230
231
232 pack(ct[:matrixBpPackedSize], Bp[:])
233 pack(ct[matrixBpPackedSize:], C[:])
234
235
236 shake128.Reset()
237 _, _ = shake128.Write(ct[:])
238 _, _ = shake128.Write(G2out[SharedKeySize:])
239 _, _ = shake128.Read(ss[:])
240 }
241
242
243
244
245
246
247 func (sk *PrivateKey) DecapsulateTo(ss, ct []byte) {
248 if len(ct) != CiphertextSize {
249 panic("ct must be of length CiphertextSize")
250 }
251 if len(ss) != SharedKeySize {
252 panic("ss must be of length SharedKeySize")
253 }
254
255 var Bp nbarByNU16
256 var C nbarByNbarU16
257
258 var W nbarByNbarU16
259 var CC nbarByNbarU16
260 var BBp nbarByNU16
261
262 var SpEpEpp [(paramN * paramNbar) + (paramN * paramNbar) + (paramNbar * paramNbar)]uint16
263 var byteSpEpEpp [2 * len(SpEpEpp)]byte
264 Sp := SpEpEpp[:paramN*paramNbar]
265 Ep := SpEpEpp[paramN*paramNbar : 2*paramN*paramNbar]
266 Epp := SpEpEpp[2*paramN*paramNbar:]
267
268 var A nByNU16
269
270 var muprime [messageSize]byte
271 var G2out [2 * SharedKeySize]byte
272
273 kprime := G2out[SharedKeySize:]
274
275
276 unpack(Bp[:], ct[0:matrixBpPackedSize])
277 unpack(C[:], ct[matrixBpPackedSize:])
278 mulBS(&W, &Bp, &sk.matrixS)
279 sub(&W, &C, &W)
280
281 decodeMessage(&muprime, &W)
282
283
284 shake128 := sha3.NewShake128()
285 _, _ = shake128.Write(sk.hpk[:])
286 _, _ = shake128.Write(muprime[:])
287 _, _ = shake128.Read(G2out[:])
288
289
290 shake128.Reset()
291 _, _ = shake128.Write([]byte{0x96})
292 _, _ = shake128.Write(G2out[:SharedKeySize])
293 _, _ = shake128.Read(byteSpEpEpp[:])
294 for i := range SpEpEpp {
295 SpEpEpp[i] = uint16(byteSpEpEpp[i*2]) | (uint16(byteSpEpEpp[(i*2)+1]) << 8)
296 }
297
298 sample(SpEpEpp[:])
299
300 expandSeedIntoA(&A, &sk.pk.seedA, &shake128)
301 mulAddSAPlusE(&BBp, Sp[:], &A, Ep[:])
302
303
304 for i := range BBp {
305 BBp[i] = BBp[i] & logQMask
306 }
307
308
309 mulAddSBPlusE(&W, Sp, &sk.pk.matrixB, Epp)
310
311
312 encodeMessage(&CC, &muprime)
313 add(&CC, &W, &CC)
314
315
316
317
318
319
320
321 selector := ctCompareU16(Bp[:], BBp[:]) | ctCompareU16(C[:], CC[:])
322
323 subtle.ConstantTimeCopy(selector, kprime[:], sk.hashInputIfDecapsFail[:])
324
325 shake128.Reset()
326 _, _ = shake128.Write(ct[:])
327 _, _ = shake128.Write(kprime[:])
328 _, _ = shake128.Read(ss[:])
329 }
330
331
332
333
334 func (sk *PrivateKey) Pack(buf []byte) {
335 if len(buf) != PrivateKeySize {
336 panic("buf must be of length PrivateKeySize")
337 }
338
339 copy(buf[:SharedKeySize], sk.hashInputIfDecapsFail[:])
340 buf = buf[SharedKeySize:]
341
342 sk.pk.Pack(buf[:PublicKeySize])
343 buf = buf[PublicKeySize:]
344
345 j := 0
346 for i := range sk.matrixS {
347 buf[j] = byte(sk.matrixS[i])
348 buf[j+1] = byte(sk.matrixS[i] >> 8)
349 j += 2
350 }
351 buf = buf[j:]
352
353 copy(buf[:], sk.hpk[:])
354 }
355
356
357
358
359 func (sk *PrivateKey) Unpack(buf []byte) {
360 if len(buf) != PrivateKeySize {
361 panic("buf must be of length PrivateKeySize")
362 }
363
364 copy(sk.hashInputIfDecapsFail[:], buf[:SharedKeySize])
365 buf = buf[SharedKeySize:]
366
367 sk.pk = new(PublicKey)
368 sk.pk.Unpack(buf[:PublicKeySize])
369 buf = buf[PublicKeySize:]
370
371 for i := range sk.matrixS {
372 sk.matrixS[i] = uint16(buf[i*2]) | (uint16(buf[(i*2)+1]) << 8)
373 }
374 buf = buf[len(sk.matrixS)*2:]
375
376 copy(sk.hpk[:], buf[:])
377 }
378
379
380
381
382 func (pk *PublicKey) Pack(buf []byte) {
383 if len(buf) != PublicKeySize {
384 panic("buf must be of length PublicKeySize")
385 }
386
387 copy(buf[:seedASize], pk.seedA[:])
388 pack(buf[seedASize:], pk.matrixB[:])
389 }
390
391
392
393
394 func (pk *PublicKey) Unpack(buf []byte) {
395 if len(buf) != PublicKeySize {
396 panic("buf must be of length PublicKeySize")
397 }
398
399 copy(pk.seedA[:], buf[:seedASize])
400 unpack(pk.matrixB[:], buf[seedASize:])
401 }
402
403
404
405 type scheme struct{}
406
407 var sch kem.Scheme = &scheme{}
408
409
410 func Scheme() kem.Scheme { return sch }
411
412 func (scheme) Name() string { return "FrodoKEM-640-SHAKE" }
413 func (*scheme) PublicKeySize() int { return PublicKeySize }
414 func (*scheme) PrivateKeySize() int { return PrivateKeySize }
415 func (*scheme) SeedSize() int { return KeySeedSize }
416 func (*scheme) SharedKeySize() int { return SharedKeySize }
417 func (*scheme) CiphertextSize() int { return CiphertextSize }
418 func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
419
420 func (sk *PrivateKey) Scheme() kem.Scheme { return sch }
421 func (pk *PublicKey) Scheme() kem.Scheme { return sch }
422
423 func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
424 var ret [PrivateKeySize]byte
425 sk.Pack(ret[:])
426 return ret[:], nil
427 }
428
429 func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
430 oth, ok := other.(*PrivateKey)
431 if !ok {
432 return false
433 }
434 if sk.pk == nil && oth.pk == nil {
435 return true
436 }
437 if sk.pk == nil || oth.pk == nil {
438 return false
439 }
440 return ctCompareU16(sk.matrixS[:], oth.matrixS[:]) == 0 &&
441 subtle.ConstantTimeCompare(sk.hashInputIfDecapsFail[:], oth.hashInputIfDecapsFail[:]) == 1 &&
442 sk.pk.Equal(oth.pk) &&
443 bytes.Equal(sk.hpk[:], oth.hpk[:])
444 }
445
446 func (pk *PublicKey) Equal(other kem.PublicKey) bool {
447 oth, ok := other.(*PublicKey)
448 if !ok {
449 return false
450 }
451 if pk == nil && oth == nil {
452 return true
453 }
454 if pk == nil || oth == nil {
455 return false
456 }
457
458 for i := range pk.matrixB {
459 if (pk.matrixB[i] & logQMask) != (oth.matrixB[i] & logQMask) {
460 return false
461 }
462 }
463 return bytes.Equal(pk.seedA[:], oth.seedA[:])
464 }
465
466 func (sk *PrivateKey) Public() kem.PublicKey {
467 return sk.pk
468 }
469
470 func (pk *PublicKey) MarshalBinary() ([]byte, error) {
471 var ret [PublicKeySize]byte
472 pk.Pack(ret[:])
473 return ret[:], nil
474 }
475
476 func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
477 return generateKeyPair(cryptoRand.Reader)
478 }
479
480 func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
481 if len(seed) != KeySeedSize {
482 panic(kem.ErrSeedSize)
483 }
484 return newKeyFromSeed(seed[:])
485 }
486
487 func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
488 ct = make([]byte, CiphertextSize)
489 ss = make([]byte, SharedKeySize)
490
491 pub, ok := pk.(*PublicKey)
492 if !ok {
493 return nil, nil, kem.ErrTypeMismatch
494 }
495 pub.EncapsulateTo(ct, ss, nil)
496 return
497 }
498
499 func (*scheme) EncapsulateDeterministically(
500 pk kem.PublicKey, seed []byte,
501 ) (ct, ss []byte, err error) {
502 if len(seed) != EncapsulationSeedSize {
503 return nil, nil, kem.ErrSeedSize
504 }
505
506 ct = make([]byte, CiphertextSize)
507 ss = make([]byte, SharedKeySize)
508
509 pub, ok := pk.(*PublicKey)
510 if !ok {
511 return nil, nil, kem.ErrTypeMismatch
512 }
513 pub.EncapsulateTo(ct, ss, seed)
514 return
515 }
516
517 func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
518 if len(ct) != CiphertextSize {
519 return nil, kem.ErrCiphertextSize
520 }
521
522 priv, ok := sk.(*PrivateKey)
523 if !ok {
524 return nil, kem.ErrTypeMismatch
525 }
526 ss := make([]byte, SharedKeySize)
527 priv.DecapsulateTo(ss, ct)
528 return ss, nil
529 }
530
531 func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
532 if len(buf) != PublicKeySize {
533 return nil, kem.ErrPubKeySize
534 }
535 var ret PublicKey
536 ret.Unpack(buf)
537 return &ret, nil
538 }
539
540 func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
541 if len(buf) != PrivateKeySize {
542 return nil, kem.ErrPrivKeySize
543 }
544 var ret PrivateKey
545 ret.Unpack(buf)
546 return &ret, nil
547 }
548
View as plain text