safe_pqc_kyber/reference/
fips202.rs

1#![allow(clippy::needless_range_loop, dead_code)]
2
3use crate::symmetric::KeccakState;
4
5pub(crate) const SHAKE128_RATE: usize = 168;
6const SHAKE256_RATE: usize = 136;
7const SHA3_256_RATE: usize = 136;
8const SHA3_512_RATE: usize =  72;
9const NROUNDS: usize = 24;
10
11fn rol(a: u64, offset: u64) -> u64 
12{
13  (a << offset) ^ (a >> (64-offset))
14}
15
16// Name:        load64
17//
18// Description: Load 8 bytes into u64 in little-endian order
19//
20// Arguments:   - const [u8] x: input byte array
21//
22// Returns the loaded 64-bit unsigned integer
23pub fn load64(x: &[u8]) -> u64
24{
25  let mut r = 0u64;
26  for i in 0..8 {
27    r |= (x[i] as u64) << (8 * i);
28  }
29  r
30}
31
32// Name:        store64
33//
34// Description: Store a 64-bit integer to a byte array in little-endian order
35//
36// Arguments:   - [u8] x: the output byte array
37//              - u64 u: input 64-bit unsigned integer
38pub fn store64(x: &mut[u8], mut u: u64)
39{
40  for i in x.iter_mut().take(8) {
41    *i = u as u8;
42    u >>= 8;
43  }
44}
45
46// Keccak round constants
47const KECCAKF_ROUNDCONSTANTS: [u64; NROUNDS] = [
48  0x0000000000000001,
49  0x0000000000008082,
50  0x800000000000808a,
51  0x8000000080008000,
52  0x000000000000808b,
53  0x0000000080000001,
54  0x8000000080008081,
55  0x8000000000008009,
56  0x000000000000008a,
57  0x0000000000000088,
58  0x0000000080008009,
59  0x000000008000000a,
60  0x000000008000808b,
61  0x800000000000008b,
62  0x8000000000008089,
63  0x8000000000008003,
64  0x8000000000008002,
65  0x8000000000000080,
66  0x000000000000800a,
67  0x800000008000000a,
68  0x8000000080008081,
69  0x8000000000008080,
70  0x0000000080000001,
71  0x8000000080008008
72];
73
74// Name:        KeccakF1600_StatePermute
75//
76// Description: The Keccak F1600 Permutation
77//
78// Arguments:   - u64 * state: in/output Keccak state
79pub fn keccakf1600_statepermute(state: &mut[u64])
80{
81  //copyFromState(A, state)
82 let mut aba = state[ 0];
83 let mut abe = state[ 1];
84 let mut abi = state[ 2];
85 let mut abo = state[ 3];
86 let mut abu = state[ 4];
87 let mut aga = state[ 5];
88 let mut age = state[ 6];
89 let mut agi = state[ 7];
90 let mut ago = state[ 8];
91 let mut agu = state[ 9];
92 let mut aka = state[10];
93 let mut ake = state[11];
94 let mut aki = state[12];
95 let mut ako = state[13];
96 let mut aku = state[14];
97 let mut ama = state[15];
98 let mut ame = state[16];
99 let mut ami = state[17];
100 let mut amo = state[18];
101 let mut amu = state[19];
102 let mut asa = state[20];
103 let mut ase = state[21];
104 let mut asi = state[22];
105 let mut aso = state[23];
106 let mut asu = state[24];
107
108  for round in (0..NROUNDS).step_by(2) {
109    // prepareTheta
110    let mut bca = aba^aga^aka^ama^asa;
111    let mut bce = abe^age^ake^ame^ase;
112    let mut bci = abi^agi^aki^ami^asi;
113    let mut bco = abo^ago^ako^amo^aso;
114    let mut bcu = abu^agu^aku^amu^asu;
115
116    //thetaRhoPiChiIotaPrepareTheta(round  , A, E)
117    let mut da = bcu^rol(bce, 1);
118    let mut de = bca^rol(bci, 1);
119    let mut di = bce^rol(bco, 1);
120    let mut d_o = bci^rol(bcu, 1);
121    let mut du = bco^rol(bca, 1);
122
123    aba ^= da;
124    bca = aba;
125    age ^= de;
126    bce = rol(age, 44);
127    aki ^= di;
128    bci = rol(aki, 43);
129    amo ^= d_o;
130    bco = rol(amo, 21);
131    asu ^= du;
132    bcu = rol(asu, 14);
133    let mut eba =   bca ^((!bce)&  bci );
134    eba ^= KECCAKF_ROUNDCONSTANTS[round];
135    let mut ebe =   bce ^((!bci)&  bco );
136    let mut ebi =   bci ^((!bco)&  bcu );
137    let mut ebo =   bco ^((!bcu)&  bca );
138    let mut ebu =   bcu ^((!bca)&  bce );
139
140    abo ^= d_o;
141    bca = rol(abo, 28);
142    agu ^= du;
143    bce = rol(agu, 20);
144    aka ^= da;
145    bci = rol(aka,  3);
146    ame ^= de;
147    bco = rol(ame, 45);
148    asi ^= di;
149    bcu = rol(asi, 61);
150    let mut ega =   bca ^((!bce)&  bci );
151    let mut ege =   bce ^((!bci)&  bco );
152    let mut egi =   bci ^((!bco)&  bcu );
153    let mut ego =   bco ^((!bcu)&  bca );
154    let mut egu =   bcu ^((!bca)&  bce );
155
156    abe ^= de;
157    bca = rol(abe,  1);
158    agi ^= di;
159    bce = rol(agi,  6);
160    ako ^= d_o;
161    bci = rol(ako, 25);
162    amu ^= du;
163    bco = rol(amu,  8);
164    asa ^= da;
165    bcu = rol(asa, 18);
166    let mut eka =   bca ^((!bce)&  bci );
167    let mut eke =   bce ^((!bci)&  bco );
168    let mut eki =   bci ^((!bco)&  bcu );
169    let mut eko =   bco ^((!bcu)&  bca );
170    let mut eku =   bcu ^((!bca)&  bce );
171
172    abu ^= du;
173    bca = rol(abu, 27);
174    aga ^= da;
175    bce = rol(aga, 36);
176    ake ^= de;
177    bci = rol(ake, 10);
178    ami ^= di;
179    bco = rol(ami, 15);
180    aso ^= d_o;
181    bcu = rol(aso, 56);
182    let mut ema =   bca ^((!bce)&  bci );
183    let mut eme =   bce ^((!bci)&  bco );
184    let mut emi =   bci ^((!bco)&  bcu );
185    let mut emo =   bco ^((!bcu)&  bca );
186    let mut emu =   bcu ^((!bca)&  bce );
187
188    abi ^= di;
189    bca = rol(abi, 62);
190    ago ^= d_o;
191    bce = rol(ago, 55);
192    aku ^= du;
193    bci = rol(aku, 39);
194    ama ^= da;
195    bco = rol(ama, 41);
196    ase ^= de;
197    bcu = rol(ase,  2);
198    let mut esa =   bca ^((!bce)&  bci );
199    let mut ese =   bce ^((!bci)&  bco );
200    let mut esi =   bci ^((!bco)&  bcu );
201    let mut eso =   bco ^((!bcu)&  bca );
202    let mut esu =   bcu ^((!bca)&  bce );
203
204    //    prepareTheta
205    bca = eba^ega^eka^ema^esa;
206    bce = ebe^ege^eke^eme^ese;
207    bci = ebi^egi^eki^emi^esi;
208    bco = ebo^ego^eko^emo^eso;
209    bcu = ebu^egu^eku^emu^esu;
210
211    //thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
212    da = bcu^rol(bce, 1);
213    de = bca^rol(bci, 1);
214    di = bce^rol(bco, 1);
215    d_o = bci^rol(bcu, 1);
216    du = bco^rol(bca, 1);
217
218    eba ^= da;
219    bca = eba;
220    ege ^= de;
221    bce = rol(ege, 44);
222    eki ^= di;
223    bci = rol(eki, 43);
224    emo ^= d_o;
225    bco = rol(emo, 21);
226    esu ^= du;
227    bcu = rol(esu, 14);
228    aba =   bca ^((!bce)&  bci );
229    aba ^= KECCAKF_ROUNDCONSTANTS[round+1];
230    abe =   bce ^((!bci)&  bco );
231    abi =   bci ^((!bco)&  bcu );
232    abo =   bco ^((!bcu)&  bca );
233    abu =   bcu ^((!bca)&  bce );
234
235    ebo ^= d_o;
236    bca = rol(ebo, 28);
237    egu ^= du;
238    bce = rol(egu, 20);
239    eka ^= da;
240    bci = rol(eka, 3);
241    eme ^= de;
242    bco = rol(eme, 45);
243    esi ^= di;
244    bcu = rol(esi, 61);
245    aga =   bca ^((!bce)&  bci );
246    age =   bce ^((!bci)&  bco );
247    agi =   bci ^((!bco)&  bcu );
248    ago =   bco ^((!bcu)&  bca );
249    agu =   bcu ^((!bca)&  bce );
250
251    ebe ^= de;
252    bca = rol(ebe, 1);
253    egi ^= di;
254    bce = rol(egi, 6);
255    eko ^= d_o;
256    bci = rol(eko, 25);
257    emu ^= du;
258    bco = rol(emu, 8);
259    esa ^= da;
260    bcu = rol(esa, 18);
261    aka =   bca ^((!bce)&  bci );
262    ake =   bce ^((!bci)&  bco );
263    aki =   bci ^((!bco)&  bcu );
264    ako =   bco ^((!bcu)&  bca );
265    aku =   bcu ^((!bca)&  bce );
266
267    ebu ^= du;
268    bca = rol(ebu, 27);
269    ega ^= da;
270    bce = rol(ega, 36);
271    eke ^= de;
272    bci = rol(eke, 10);
273    emi ^= di;
274    bco = rol(emi, 15);
275    eso ^= d_o;
276    bcu = rol(eso, 56);
277    ama =   bca ^((!bce)&  bci );
278    ame =   bce ^((!bci)&  bco );
279    ami =   bci ^((!bco)&  bcu );
280    amo =   bco ^((!bcu)&  bca );
281    amu =   bcu ^((!bca)&  bce );
282
283    ebi ^= di;
284    bca = rol(ebi, 62);
285    ego ^= d_o;
286    bce = rol(ego, 55);
287    eku ^= du;
288    bci = rol(eku, 39);
289    ema ^= da;
290    bco = rol(ema, 41);
291    ese ^= de;
292    bcu = rol(ese, 2);
293    asa =   bca ^((!bce)&  bci );
294    ase =   bce ^((!bci)&  bco );
295    asi =   bci ^((!bco)&  bcu );
296    aso =   bco ^((!bcu)&  bca );
297    asu =   bcu ^((!bca)&  bce );
298  } 
299
300  state[ 0] = aba;
301  state[ 1] = abe;
302  state[ 2] = abi;
303  state[ 3] = abo;
304  state[ 4] = abu;
305  state[ 5] = aga;
306  state[ 6] = age;
307  state[ 7] = agi;
308  state[ 8] = ago;
309  state[ 9] = agu;
310  state[10] = aka;
311  state[11] = ake;
312  state[12] = aki;
313  state[13] = ako;
314  state[14] = aku;
315  state[15] = ama;
316  state[16] = ame;
317  state[17] = ami;
318  state[18] = amo;
319  state[19] = amu;
320  state[20] = asa;
321  state[21] = ase;
322  state[22] = asi;
323  state[23] = aso;
324  state[24] = asu;
325}
326
327// Name:        keccak_squeezeblocks
328//
329// Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each.
330//              Modifies the state. Can be called multiple times to keep squeezing,
331//              i.e., is incremental.
332//
333// Arguments:   - [u8] h:             output blocks
334//              - u64 nblocks:        number of blocks to be squeezed (written to h)
335//              - u64 *s:             in/output Keccak state
336//              - usize r:            rate in bytes (e.g., 168 for SHAKE128)
337pub(crate) fn keccak_squeezeblocks(h: &mut[u8], mut nblocks: usize, s: &mut [u64], r: usize)
338{
339  let mut idx = 0usize;
340  while nblocks > 0 {
341    keccakf1600_statepermute(s);
342    for i in 0..r/8 {
343      store64(&mut h[idx+8*i..], s[i])
344    }
345    idx += r;
346    nblocks -= 1;
347  }
348}
349
350// Name:        shake128_squeezeblocks
351//
352// Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of
353//              SHAKE128_RATE bytes each. Can be called multiple times
354//              to keep squeezing. Assumes new block has not yet been
355//              started (state->pos = SHAKE128_RATE).
356//
357// Arguments:   - [u8] out: pointer to output blocks
358//              - u64 nblocks: number of blocks to be squeezed (written to output)
359//              - KeccakState state: pointer to input/output Keccak state
360pub(crate) fn shake128_squeezeblocks(out: &mut[u8], nblocks: usize, state: &mut KeccakState)
361{
362  keccak_squeezeblocks(out, nblocks, &mut state.s, SHAKE128_RATE);
363}
364
365// Name:        shake256
366//
367// Description: SHAKE256 XOF with non-incremental API
368//
369// Arguments:   - [u8] output:      output
370//              - usize outlen:  requested output length in bytes
371//              - [u8] input: input
372//              - usize inlen:   length of input in bytes
373pub(crate) fn shake256(out: &mut[u8], mut outlen: usize, input: &[u8], inlen: usize)
374{
375  let mut state = KeccakState::new();
376  let mut idx = 0;
377  shake256_absorb_once(&mut state, input, inlen);
378  let nblocks = outlen/SHAKE256_RATE;
379  shake256_squeezeblocks(&mut out[idx..], nblocks, &mut state);
380  outlen -= nblocks*SHAKE256_RATE;
381  idx += nblocks*SHAKE256_RATE;
382  shake256_squeeze(&mut out[idx..], outlen, &mut state);
383}
384
385// Name:        sha3_256
386//
387// Description: SHA3-256 with non-incremental API
388//
389// Arguments:   - [u8] h:      output (32 bytes)
390//              - const [u8] input: input
391//              - usize inlen:   length of input in bytes
392pub(crate) fn sha3_256(h: &mut[u8], input: &[u8], inlen: usize)
393{
394  let mut s = [0u64; 25]; 
395  keccak_absorb_once(&mut s, SHA3_256_RATE, input, inlen, 0x06);
396  keccakf1600_statepermute(&mut s);
397  for i in 0..4 {
398    store64(&mut h[8*i..], s[i]);
399  }
400}
401
402// Name:        sha3_512
403//
404// Description: SHA3-512 with non-incremental API
405//
406// Arguments:   - [u8] h:      output (64 bytes)
407//              - const [u8] input: input
408//              - usize inlen:   length of input in bytes
409pub(crate) fn sha3_512(h: &mut[u8], input: &[u8], inlen: usize)
410{
411  let mut s = [0u64; 25]; 
412  keccak_absorb_once(&mut s, SHA3_512_RATE, input, inlen, 0x06);
413  keccakf1600_statepermute(&mut s);
414  for i in 0..8 {
415    store64(&mut h[8*i..], s[i]);
416  }
417}
418
419
420
421// Name:        keccak_finalize
422//
423// Description: Finalize absorb step.
424//
425// Arguments:   - u64 s: pointer to Keccak state
426//              - usize pos: position in current block to be absorbed
427//              - usize r: rate in bytes (e.g., 168 for SHAKE128)
428//              - u8 p: domain separation byte
429fn keccak_finalize(s: &mut[u64], pos: usize, r: usize, p: u8)
430{
431  s[pos/8] ^= (p as u64) << 8*(pos%8);
432  s[r/8-1] ^= 1u64 << 63;
433}
434
435// Name:        keccak_absorb_once
436//
437// Description: Absorb step of Keccak;
438//              non-incremental, starts by zeroeing the state.
439//
440// Arguments:   - u64 *s:             (uninitialized) output Keccak state
441//              - usize r:          rate in bytes (e.g., 168 for SHAKE128)
442//              - const [u8] input:  input to be absorbed into s
443//              - u64 mlen: length of input in bytes
444//              - [u8]  p:         domain-separation byte for different Keccak-derived functions
445pub(crate) fn keccak_absorb_once(
446  s: &mut[u64], 
447  r: usize, 
448  input: &[u8], 
449  mut inlen: 
450  usize, 
451  p: u8)
452{
453  // Zero State
454  for i in s.iter_mut() {
455    *i = 0;
456  }
457
458  let mut idx = 0usize;
459  while inlen >= r {
460    for i in 0..(r/8) {
461      s[i] ^= load64(&input[idx+8*i..]);
462    }
463    idx += r;
464    inlen -= r;
465    keccakf1600_statepermute(s);
466  }
467
468  for i in 0..inlen {
469    s[i/8] ^= (input[idx+i] as u64) << 8*(i%8);
470  }
471  s[inlen/8] ^= (p as u64) << 8*(inlen%8);
472  s[(r-1)/8] ^= 1u64 << 63;
473}
474
475// Name:        keccak_squeeze
476//
477// Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each.
478//              Modifies the state. Can be called multiple times to keep squeezing,
479//              i.e., is incremental.
480//
481// Arguments:   - [u8] out:             output blocks
482//              - u64 nblocks:        number of blocks to be squeezed (written to out)
483//              - u64 *s:             in/output Keccak state
484//                usize pos: number of bytes in current block already squeezed
485//              - usize r:            rate in bytes (e.g., 168 for SHAKE128)
486// Returns new position pos in current block
487pub(crate) fn keccak_squeeze(
488  out: &mut[u8], 
489  mut outlen: usize, 
490  s: &mut [u64], 
491  mut pos: usize, 
492  r: usize
493) -> usize
494{
495  let mut idx = 0;
496  while outlen > 0 {
497    if pos == r {
498      keccakf1600_statepermute(s);
499      pos = 0
500    }
501    let mut i = pos;
502    while i < r  && i < pos+outlen {
503      out[idx] = (s[i/8] >> 8*(i%8)) as u8;
504      i += 1;
505      idx += 1;
506    }
507    outlen -= i-pos;
508    pos = i;
509  }
510  pos
511}
512
513// Name:        shake128_init
514//
515// Description: Initilizes Keccak state for use as SHAKE128 XOF
516//
517// Arguments:   - keccak_state state: (uninitialized) Keccak state
518fn shake128_init(state: &mut KeccakState)
519{
520  state.reset()
521}
522
523
524// Name:        shake128_finalize
525//
526// Description: Finalize absorb step of the SHAKE128 XOF.
527//
528// Arguments:   - keccak_state state: pointer to Keccak state
529fn shake128_finalize(state: &mut KeccakState)
530{
531  keccak_finalize(&mut state.s, state.pos, SHAKE128_RATE, 0x1F);
532  state.pos = SHAKE128_RATE;
533}
534
535// Name:        shake128_squeeze
536//
537// Description: Squeeze step of SHAKE128 XOF. Squeezes arbitraily many
538//              bytes. Can be called multiple times to keep squeezing.
539//
540// Arguments:   - [u8] out: pointer to output blocks
541//              - usize outlen : number of bytes to be squeezed (written to output)
542//              - keccak_state s: pointer to input/output Keccak state
543fn shake128_squeeze(out: &mut[u8], outlen: usize, state: &mut KeccakState)
544{
545  state.pos = keccak_squeeze(out, outlen, &mut state.s, state.pos, SHAKE128_RATE);
546}
547
548// Name:        shake128_absorb_once
549//
550// Description: Initialize, absorb into and finalize SHAKE128 XOF; non-incremental.
551//
552// Arguments:   - keccak_state state: pointer to (uninitialized) output Keccak state
553//              - const [u8] in: input to be absorbed into s
554//              - usize inlen: length of input in bytes
555pub(crate) fn shake128_absorb_once(state: &mut KeccakState, input: &[u8], inlen: usize)
556{
557  keccak_absorb_once(&mut state.s, SHAKE128_RATE, input, inlen, 0x1F);
558  state.pos = SHAKE128_RATE;
559}
560
561fn shake256_init(state: &mut KeccakState) {
562  state.reset();
563}
564
565fn shake256_finalize(state: &mut KeccakState)
566{
567  keccak_finalize(&mut state.s, state.pos, SHAKE256_RATE, 0x1F);
568  state.pos = SHAKE256_RATE;
569}
570
571fn shake256_squeeze(out: &mut[u8], outlen: usize, state: &mut KeccakState)
572{
573  state.pos = keccak_squeeze(out, outlen, &mut state.s, state.pos, SHAKE256_RATE);
574}
575
576fn shake256_absorb_once(state: &mut KeccakState, input: &[u8], inlen: usize)
577{
578  keccak_absorb_once(&mut state.s, SHAKE256_RATE, input, inlen, 0x1F);
579  state.pos = SHAKE256_RATE;
580}
581
582fn shake256_squeezeblocks(out: &mut[u8], nblocks: usize, state: &mut KeccakState)
583{
584  keccak_squeezeblocks(out, nblocks, &mut state.s, SHAKE256_RATE);
585}
586
587fn shake128(out: &mut[u8], mut outlen: usize, input: &[u8], inlen: usize)
588{
589  let mut state = KeccakState::new();
590  let mut idx = 0;
591  shake128_absorb_once(&mut state, input, inlen);
592  let nblocks = outlen/SHAKE128_RATE;
593  shake128_squeezeblocks(&mut out[idx..], nblocks, &mut state);
594  outlen -= nblocks*SHAKE128_RATE;
595  idx += nblocks*SHAKE128_RATE;
596  shake128_squeeze(&mut out[idx..], outlen, &mut state);
597}
598