1use crate::{common::common::QRC_SYSTEM_IS_LITTLE_ENDIAN, digest::sha3::{qrc_cshake_initialize, qrc_cshake_squeezeblocks, qrc_keccak_absorb_key_custom, qrc_keccak_dispose, qrc_keccak_finalize, qrc_keccak_initialize_state, qrc_keccak_update, qrc_kmac_finalize, qrc_kmac_initialize, qrc_kmac_update, QrcKeccakRate, QrcKeccakState, QRC_KECCAK_512_RATE, QRC_KECCAK_KMAC_DOMAIN_ID, QRC_KECCAK_PERMUTATION_MIN_ROUNDS, QRC_KECCAK_STATE_SIZE}, tools::intutils::{qrc_intutils_clear64, qrc_intutils_copy64, qrc_intutils_copy8, qrc_intutils_le32to8, qrc_intutils_le64to8, qrc_intutils_le8to64, qrc_intutils_min, qrc_intutils_rotl64, qrc_intutils_transform_8to64, qrc_intutils_verify, qrc_intutils_xor}};
29
30use core::{mem::size_of, default::Default};
31
32#[cfg(feature = "no_std")]
33use alloc::vec::Vec;
34
35pub const QRC_CSX_AUTHENTICATED: bool = true;
40
41pub const QRC_CSX_AUTH_KMAC: bool = false;
47pub const QRC_CSX_KPA_AUTHENTICATION: bool = false;
48
49pub const QRC_CSX_AUTH_KMACR12: bool = true;
55
56pub const QRC_CSX_BLOCK_SIZE: usize = 128;
61
62pub const QRC_CSX_INFO_SIZE: usize = 48;
67
68pub const QRC_CSX_KEY_SIZE: usize = 64;
73
74pub const QRC_CSX_MAC_SIZE: usize = 64;
79
80pub const QRC_CSX_NONCE_SIZE: usize = 16;
85
86pub const QRC_CSX_STATE_SIZE: usize = 16;
91
92#[derive(Clone)]
101pub struct QrcCsxKeyparams {
102 pub key: Vec<u8>, pub keylen: usize, pub nonce: Vec<u8>, pub info: Vec<u8>, pub infolen: usize, }
108impl Default for QrcCsxKeyparams{
109 fn default() -> Self {
110 Self {
111 key: Default::default(),
112 keylen: Default::default(),
113 nonce: Default::default(),
114 info: Default::default(),
115 infolen: Default::default(),
116 }
117 }
118}
119
120#[derive(Clone)]
125pub struct QrcCsxState {
126 pub state: [u64; QRC_CSX_STATE_SIZE], pub kstate: QrcKeccakState, pub counter: u64, pub encrypt: bool, }
132impl Default for QrcCsxState{
133 fn default() -> Self {
134 Self {
135 state: Default::default(),
136 kstate: Default::default(),
137 counter: Default::default(),
138 encrypt: Default::default(),
139 }
140 }
141}
142
143pub fn qrc_csx_dispose(ctx: &mut QrcCsxState) {
154
155 if QRC_CSX_AUTHENTICATED {
157 qrc_keccak_dispose(&mut ctx.kstate);
158 }
159
160 qrc_intutils_clear64(&mut ctx.state, QRC_CSX_STATE_SIZE);
161 ctx.counter = 0;
162 ctx.encrypt = false;
163}
164
165pub fn qrc_csx_initialize(ctx: &mut QrcCsxState, keyparams: QrcCsxKeyparams, encryption: bool) {
173 ctx.counter = 0;
174 ctx.encrypt = encryption;
175
176 if QRC_CSX_AUTHENTICATED {
177
178 let kstate = &mut QrcKeccakState::default();
179 let buf = &mut [0u8; QRC_KECCAK_512_RATE];
180 let cpk = &mut [0u8; QRC_CSX_KEY_SIZE];
181 let mck = &mut [0u8; QRC_CSX_KEY_SIZE];
182 let nme = &mut [0u8; CSX_NAME_LENGTH];
183
184 if keyparams.infolen == 0 {
186 qrc_intutils_copy8(nme, &CSX_NAME, CSX_NAME_LENGTH);
187 } else {
188 let inflen = qrc_intutils_min(keyparams.infolen, CSX_NAME_LENGTH);
189 qrc_intutils_copy8(nme, &keyparams.info, inflen);
190 }
191
192 let rate = QrcKeccakRate::QrcKeccakRate512 as usize;
194 qrc_cshake_initialize(kstate, rate, &keyparams.key, keyparams.keylen, nme, CSX_NAME_LENGTH, &[], 0);
195
196 qrc_cshake_squeezeblocks(kstate, rate, buf, 1);
198 qrc_intutils_copy8(cpk, buf, QRC_CSX_KEY_SIZE);
199 csx_load_key(ctx, cpk, &keyparams.nonce, &CSX_INFO);
200
201 qrc_cshake_squeezeblocks(kstate, rate, buf, 1);
203 qrc_intutils_copy8(mck, buf, QRC_CSX_KEY_SIZE);
204
205 qrc_intutils_clear64(&mut ctx.kstate.state, QRC_KECCAK_STATE_SIZE);
207
208 if QRC_CSX_AUTH_KMACR12 {
209 qrc_keccak_initialize_state(&mut ctx.kstate);
210 qrc_keccak_absorb_key_custom(&mut ctx.kstate, rate, mck, QRC_CSX_KEY_SIZE, &[], 0, &CSX_KMACR12_NAME, CSX_NAME_LENGTH, QRC_KECCAK_PERMUTATION_MIN_ROUNDS);
211 } else {
212 qrc_kmac_initialize(&mut ctx.kstate, rate, mck, QRC_CSX_KEY_SIZE, &mut [], 0);
213 }
214
215 } else {
216
217 let inf = &mut [0u8; QRC_CSX_INFO_SIZE];
218
219 if keyparams.infolen == 0 {
221 qrc_intutils_copy8(inf, &CSX_INFO, QRC_CSX_INFO_SIZE);
222 } else {
223 let inflen = qrc_intutils_min(keyparams.infolen, QRC_CSX_INFO_SIZE);
224 qrc_intutils_copy8(inf, &keyparams.info, inflen);
225 }
226
227 qrc_intutils_clear64(&mut ctx.state, QRC_CSX_STATE_SIZE);
228 csx_load_key(ctx, &keyparams.key, &keyparams.nonce, inf);
229 }
230}
231
232pub fn qrc_csx_set_associated(ctx: &mut QrcCsxState, data: &[u8], length: usize) {
245 if length != 0 {
246 let code = &mut [0u8; size_of::<u32>()];
247
248 csx_mac_update(ctx, data, length);
250 qrc_intutils_le32to8(code, length as u32);
252 csx_mac_update(ctx, code, size_of::<u32>());
253 }
254}
255
256pub fn qrc_csx_transform(ctx: &mut QrcCsxState, output: &mut [u8], input: &[u8], length: usize) -> bool {
272 let mut res = true;
273
274 if QRC_CSX_AUTHENTICATED {
275
276 let ncopy = &mut [0u8; QRC_CSX_NONCE_SIZE];
277 res = false;
278
279 qrc_intutils_le64to8(ncopy, ctx.state[12]);
281 qrc_intutils_le64to8(&mut ncopy[size_of::<u64>()..], ctx.state[13]);
282
283 ctx.counter += length as u64;
285
286 csx_mac_update(ctx, ncopy, QRC_CSX_NONCE_SIZE);
288
289 if ctx.encrypt {
290 csx_transform(ctx, output, input, length);
292
293 csx_mac_update(ctx, output, length);
295
296 csx_finalize(ctx, &mut output[length..]);
298 res = true;
299 } else {
300 let code= &mut [0u8; QRC_CSX_MAC_SIZE];
301
302 csx_mac_update(ctx, input, length);
304
305 csx_finalize(ctx, code);
307
308 if qrc_intutils_verify(code, &input[length..], QRC_CSX_MAC_SIZE) == 0 {
310 csx_transform(ctx, output, input, length);
312 res = true;
313 }
314 }
315 } else {
316 csx_transform(ctx, output, input, length);
317 }
318
319 return res;
320}
321
322pub fn qrc_csx_extended_transform(ctx: &mut QrcCsxState, output: &mut [u8], input: &[u8], length: usize, finalize: bool) -> bool {
343 let mut res = true;
344
345 if QRC_CSX_AUTHENTICATED {
346
347 let ncopy = &mut [0u8; QRC_CSX_NONCE_SIZE];
348 res = false;
349
350 qrc_intutils_le64to8(ncopy, ctx.state[12]);
352 qrc_intutils_le64to8(&mut ncopy[size_of::<u64>()..], ctx.state[13]);
353
354 ctx.counter += length as u64;
356
357 csx_mac_update(ctx, ncopy, QRC_CSX_NONCE_SIZE);
359
360 if ctx.encrypt {
361 csx_transform(ctx, output, input, length);
363
364 csx_mac_update(ctx, output, length);
366
367 if finalize {
368 csx_finalize(ctx, &mut output[length..]);
370 }
371
372 res = true;
373 } else {
374 let code = &mut [0u8; QRC_CSX_MAC_SIZE];
375
376 csx_mac_update(ctx, input, length);
378
379 if finalize {
380 csx_finalize(ctx, code);
382
383 if qrc_intutils_verify(code, &input[length..], QRC_CSX_MAC_SIZE) == 0 {
385 csx_transform(ctx, output, input, length);
387 res = true;
388 }
389 } else {
390 csx_transform(ctx, output, input, length);
392 res = true;
393 }
394 }
395
396 } else {
397 csx_transform(ctx, output, input, length);
398 }
399
400 return res;
401}
402
403const CSX_ROUND_COUNT: usize = 40;
408const CSX_NAME_LENGTH: usize = 14;
413
414const CSX_INFO: [u8; QRC_CSX_INFO_SIZE] = [
415 0x43, 0x53, 0x58, 0x35, 0x31, 0x32, 0x20, 0x4B, 0x4D, 0x41, 0x43, 0x20, 0x61, 0x75, 0x74, 0x68,
416 0x65, 0x6E, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20,
417 0x31, 0x63, 0x20, 0x43, 0x45, 0x58, 0x2B, 0x2B, 0x20, 0x6C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79
418];
419
420const CSX_NAME: [u8; CSX_NAME_LENGTH] = [
421 0x43, 0x53, 0x58, 0x35, 0x31, 0x32, 0x2D, 0x4B, 0x4D, 0x41, 0x43, 0x35, 0x31, 0x32
422];
423
424const CSX_KMACR12_NAME: [u8; CSX_NAME_LENGTH] = [
425 0x43, 0x53, 0x58, 0x35, 0x31, 0x32, 0x2D, 0x4B, 0x4D, 0x41, 0x43, 0x52, 0x31, 0x32
426];
427
428fn csx_increment(ctx: &mut QrcCsxState) {
429 ctx.state[12] = ctx.state[12].wrapping_add(1);
430
431 if ctx.state[12] == 0 {
432 ctx.state[13] = ctx.state[13].wrapping_add(1);
433 }
434}
435
436fn csx_permute_p1024c(ctx: QrcCsxState, output: &mut [u8]) {
437 let mut x0 = ctx.state[0];
438 let mut x1 = ctx.state[1];
439 let mut x2 = ctx.state[2];
440 let mut x3 = ctx.state[3];
441 let mut x4 = ctx.state[4];
442 let mut x5 = ctx.state[5];
443 let mut x6 = ctx.state[6];
444 let mut x7 = ctx.state[7];
445 let mut x8 = ctx.state[8];
446 let mut x9 = ctx.state[9];
447 let mut x10 = ctx.state[10];
448 let mut x11 = ctx.state[11];
449 let mut x12 = ctx.state[12];
450 let mut x13 = ctx.state[13];
451 let mut x14 = ctx.state[14];
452 let mut x15 = ctx.state[15];
453 let mut ctr = CSX_ROUND_COUNT;
454
455 while ctr != 0 {
466 x0 = x0.wrapping_add(x4);
468 x12 = qrc_intutils_rotl64(x12 ^ x0, 38);
469 x8 = x8.wrapping_add(x12);
470 x4 = qrc_intutils_rotl64(x4 ^ x8, 19);
471 x0 = x0.wrapping_add(x4);
472 x12 = qrc_intutils_rotl64(x12 ^ x0, 10);
473 x8 = x8.wrapping_add(x12);
474 x4 = qrc_intutils_rotl64(x4 ^ x8, 55);
475 x1 = x1.wrapping_add(x5);
476 x13 = qrc_intutils_rotl64(x13 ^ x1, 33);
477 x9 = x9.wrapping_add(x13);
478 x5 = qrc_intutils_rotl64(x5 ^ x9, 4);
479 x1 = x1.wrapping_add(x5);
480 x13 = qrc_intutils_rotl64(x13 ^ x1, 51);
481 x9 = x9.wrapping_add(x13);
482 x5 = qrc_intutils_rotl64(x5 ^ x9, 13);
483 x2 = x2.wrapping_add(x6);
484 x14 = qrc_intutils_rotl64(x14 ^ x2, 16);
485 x10 = x10.wrapping_add(x14);
486 x6 = qrc_intutils_rotl64(x6 ^ x10, 34);
487 x2 = x2.wrapping_add(x6);
488 x14 = qrc_intutils_rotl64(x14 ^ x2, 56);
489 x10 = x10.wrapping_add(x14);
490 x6 = qrc_intutils_rotl64(x6 ^ x10, 51);
491 x3 = x3.wrapping_add(x7);
492 x15 = qrc_intutils_rotl64(x15 ^ x3, 4);
493 x11 = x11.wrapping_add(x15);
494 x7 = qrc_intutils_rotl64(x7 ^ x11, 53);
495 x3 = x3.wrapping_add(x7);
496 x15 = qrc_intutils_rotl64(x15 ^ x3, 42);
497 x11 = x11.wrapping_add(x15);
498 x7 = qrc_intutils_rotl64(x7 ^ x11, 41);
499 x0 = x0.wrapping_add(x5);
501 x15 = qrc_intutils_rotl64(x15 ^ x0, 34);
502 x10 = x10.wrapping_add(x15);
503 x5 = qrc_intutils_rotl64(x5 ^ x10, 41);
504 x0 = x0.wrapping_add(x5);
505 x15 = qrc_intutils_rotl64(x15 ^ x0, 59);
506 x10 = x10.wrapping_add(x15);
507 x5 = qrc_intutils_rotl64(x5 ^ x10, 17);
508 x1 = x1.wrapping_add(x6);
509 x12 = qrc_intutils_rotl64(x12 ^ x1, 23);
510 x11 = x11.wrapping_add(x12);
511 x6 = qrc_intutils_rotl64(x6 ^ x11, 31);
512 x1 = x1.wrapping_add(x6);
513 x12 = qrc_intutils_rotl64(x12 ^ x1, 37);
514 x11 = x11.wrapping_add(x12);
515 x6 = qrc_intutils_rotl64(x6 ^ x11, 20);
516 x2 = x2.wrapping_add(x7);
517 x13 = qrc_intutils_rotl64(x13 ^ x2, 31);
518 x8 = x8.wrapping_add(x13);
519 x7 = qrc_intutils_rotl64(x7 ^ x8, 44);
520 x2 = x2.wrapping_add(x7);
521 x13 = qrc_intutils_rotl64(x13 ^ x2, 47);
522 x8 = x8.wrapping_add(x13);
523 x7 = qrc_intutils_rotl64(x7 ^ x8, 46);
524 x3 = x3.wrapping_add(x4);
525 x14 = qrc_intutils_rotl64(x14 ^ x3, 12);
526 x9 = x9.wrapping_add(x14);
527 x4 = qrc_intutils_rotl64(x4 ^ x9, 47);
528 x3 = x3.wrapping_add(x4);
529 x14 = qrc_intutils_rotl64(x14 ^ x3, 44);
530 x9 = x9.wrapping_add(x14);
531 x4 = qrc_intutils_rotl64(x4 ^ x9, 30);
532 ctr -= 2;
533 }
534
535 qrc_intutils_le64to8(output, x0.wrapping_add(ctx.state[0]));
536 qrc_intutils_le64to8(&mut output[8..], x1.wrapping_add(ctx.state[1]));
537 qrc_intutils_le64to8(&mut output[16..], x2.wrapping_add(ctx.state[2]));
538 qrc_intutils_le64to8(&mut output[24..], x3.wrapping_add(ctx.state[3]));
539 qrc_intutils_le64to8(&mut output[32..], x4.wrapping_add(ctx.state[4]));
540 qrc_intutils_le64to8(&mut output[40..], x5.wrapping_add(ctx.state[5]));
541 qrc_intutils_le64to8(&mut output[48..], x6.wrapping_add(ctx.state[6]));
542 qrc_intutils_le64to8(&mut output[56..], x7.wrapping_add(ctx.state[7]));
543 qrc_intutils_le64to8(&mut output[64..], x8.wrapping_add(ctx.state[8]));
544 qrc_intutils_le64to8(&mut output[72..], x9.wrapping_add(ctx.state[9]));
545 qrc_intutils_le64to8(&mut output[80..], x10.wrapping_add(ctx.state[10]));
546 qrc_intutils_le64to8(&mut output[88..], x11.wrapping_add(ctx.state[11]));
547 qrc_intutils_le64to8(&mut output[96..], x12.wrapping_add(ctx.state[12]));
548 qrc_intutils_le64to8(&mut output[104..], x13.wrapping_add(ctx.state[13]));
549 qrc_intutils_le64to8(&mut output[112..], x14.wrapping_add(ctx.state[14]));
550 qrc_intutils_le64to8(&mut output[120..], x15.wrapping_add(ctx.state[15]));
551}
552
553fn csx_mac_update(ctx: &mut QrcCsxState, input: &[u8], length: usize) {
554 let rate = QrcKeccakRate::QrcKeccakRate512 as usize;
555 if QRC_CSX_AUTH_KMACR12 {
556 qrc_keccak_update(&mut ctx.kstate, rate, input, length, QRC_KECCAK_PERMUTATION_MIN_ROUNDS);
557 } else {
558 qrc_kmac_update(&mut ctx.kstate, rate, input, length);
559 }
560}
561
562fn csx_transform(ctx: &mut QrcCsxState, output: &mut [u8], input: &[u8], mut length: usize) {
563 let mut oft = 0;
564
565 while length >= QRC_CSX_BLOCK_SIZE {
567 csx_permute_p1024c(ctx.clone(), &mut output[oft..]);
568 qrc_intutils_xor(&mut output[oft..], &input[oft..], QRC_CSX_BLOCK_SIZE);
569 csx_increment(ctx);
570 oft += QRC_CSX_BLOCK_SIZE;
571 length -= QRC_CSX_BLOCK_SIZE;
572 }
573
574 if length != 0 {
576 let tmp = &mut [0u8; QRC_CSX_BLOCK_SIZE];
577 csx_permute_p1024c(ctx.clone(), tmp);
578 csx_increment(ctx);
579 qrc_intutils_copy8(&mut output[oft..], tmp, length);
580 qrc_intutils_xor(&mut output[oft..], &input[oft..], length);
581 }
582}
583
584fn csx_load_key(ctx: &mut QrcCsxState, key: &[u8], nonce: &[u8], code: &[u8]) {
585 if QRC_SYSTEM_IS_LITTLE_ENDIAN {
586 qrc_intutils_copy64(&mut ctx.state, &qrc_intutils_transform_8to64(key), 8);
587 qrc_intutils_copy64(&mut ctx.state[8..], &qrc_intutils_transform_8to64(code), 4);
588 qrc_intutils_copy64(&mut ctx.state[12..], &qrc_intutils_transform_8to64(nonce), 2);
589 qrc_intutils_copy64(&mut ctx.state[14..], &qrc_intutils_transform_8to64(&code[32..]), 2);
590 } else {
591 ctx.state[0] = qrc_intutils_le8to64(key);
592 ctx.state[1] = qrc_intutils_le8to64(&key[8..]);
593 ctx.state[2] = qrc_intutils_le8to64(&key[16..]);
594 ctx.state[3] = qrc_intutils_le8to64(&key[24..]);
595 ctx.state[4] = qrc_intutils_le8to64(&key[32..]);
596 ctx.state[5] = qrc_intutils_le8to64(&key[40..]);
597 ctx.state[6] = qrc_intutils_le8to64(&key[48..]);
598 ctx.state[7] = qrc_intutils_le8to64(&key[56..]);
599 ctx.state[8] = qrc_intutils_le8to64(code);
600 ctx.state[9] = qrc_intutils_le8to64(&code[8..]);
601 ctx.state[10] = qrc_intutils_le8to64(&code[16..]);
602 ctx.state[11] = qrc_intutils_le8to64(&code[24..]);
603 ctx.state[12] = qrc_intutils_le8to64(nonce);
604 ctx.state[13] = qrc_intutils_le8to64(&nonce[8..]);
605 ctx.state[14] = qrc_intutils_le8to64(&code[32..]);
606 ctx.state[15] = qrc_intutils_le8to64(&code[40..]);
607 }
608}
609
610fn csx_finalize(ctx: &mut QrcCsxState, output: &mut [u8]) {
611 let ctr = &mut [0u8; size_of::<u64>()];
612
613 qrc_intutils_le64to8(ctr, ctx.counter);
614 csx_mac_update(ctx, ctr, size_of::<u64>());
615
616 let rate = QrcKeccakRate::QrcKeccakRate512 as usize;
617 if QRC_CSX_AUTH_KMACR12 {
618 qrc_keccak_update(&mut ctx.kstate, rate, ctr, size_of::<u64>(), QRC_KECCAK_PERMUTATION_MIN_ROUNDS);
620 qrc_keccak_finalize(&mut ctx.kstate, rate, output, QRC_CSX_MAC_SIZE, QRC_KECCAK_KMAC_DOMAIN_ID as usize, QRC_KECCAK_PERMUTATION_MIN_ROUNDS);
622 } else {
623 qrc_kmac_finalize(&mut ctx.kstate, rate, output, QRC_CSX_MAC_SIZE);
625 }
626}