Skip to content

Commit 9a13375

Browse files
authored
Merge pull request #708 from MarekKnapek/KangarooTwelve
KangarooTwelve
2 parents 4db24a7 + 6832f3c commit 9a13375

File tree

7 files changed

+446
-145
lines changed

7 files changed

+446
-145
lines changed

doc/crypt.tex

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3143,6 +3143,21 @@ \subsection{TurboSHAKE}
31433143
The init function \code{turbo\_shake\_init()} is implemented as a macro which calls \code{sha3\_shake\_init()}.
31443144

31453145

3146+
\subsection{KangarooTwelve}
3147+
Another variation of SHA3 SHAKE is KangarooTwelve, which has been specified in \href{https://datatracker.ietf.org/doc/rfc9861/}{\texttt{RFC 9861}}.
3148+
3149+
The API works equivalent to the one of SHA3 SHAKE, where the APIs only have a different name. Additionally, KangarooTwelve supports customization. You can append any or none customization bytes after all input bytes and before squeezing any output digest bytes.
3150+
3151+
\begin{small}
3152+
\begin{verbatim}
3153+
int kangaroo_twelve_init(hash_state *md, int num);
3154+
int kangaroo_twelve_process(hash_state *md, const unsigned char *in, unsigned long inlen);
3155+
int kangaroo_twelve_customization(hash_state *md, const unsigned char *in, unsigned long inlen);
3156+
int kangaroo_twelve_done(hash_state *md, unsigned char *out, unsigned long outlen);
3157+
\end{verbatim}
3158+
\end{small}
3159+
3160+
31463161
\mysection{Extended Tiger API}
31473162

31483163
The Tiger and Tiger2 hash algorithms \url{http://www.cs.technion.ac.il/~biham/Reports/Tiger/} specify the possibility to run the algorithm with

src/hashes/sha3.c

Lines changed: 153 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,19 +353,19 @@ int keccak_done(hash_state *md, unsigned char *out)
353353
#endif
354354

355355
#ifdef LTC_SHA3
356-
static LTC_INLINE int s_sha3_shake_done(hash_state *md, unsigned char *out, unsigned long outlen, process_fn proc_f)
356+
static LTC_INLINE int s_sha3_shake_done(hash_state *md, unsigned char *out, unsigned long outlen, unsigned char domain, process_fn proc_f)
357357
{
358358
/* IMPORTANT NOTE: sha3_shake_done can be called many times */
359359
unsigned long idx;
360360
unsigned i;
361361

362362
if (outlen == 0) return CRYPT_OK; /* nothing to do */
363-
LTC_ARGCHK(md != NULL);
363+
LTC_ARGCHK(md != NULL);
364364
LTC_ARGCHK(out != NULL);
365365

366366
if (!md->sha3.xof_flag) {
367367
/* shake_xof operation must be done only once */
368-
md->sha3.s[md->sha3.word_index] ^= (md->sha3.saved ^ (CONST64(0x1F) << (md->sha3.byte_index * 8)));
368+
md->sha3.s[md->sha3.word_index] ^= (md->sha3.saved ^ (((ulong64)(domain)) << (md->sha3.byte_index * 8)));
369369
md->sha3.s[SHA3_KECCAK_SPONGE_WORDS - md->sha3.capacity_words - 1] ^= CONST64(0x8000000000000000);
370370
proc_f(md->sha3.s);
371371
/* store sha3.s[] as little-endian bytes into sha3.sb */
@@ -392,13 +392,13 @@ static LTC_INLINE int s_sha3_shake_done(hash_state *md, unsigned char *out, unsi
392392

393393
int sha3_shake_done(hash_state *md, unsigned char *out, unsigned long outlen)
394394
{
395-
return s_sha3_shake_done(md, out, outlen, s_keccakf);
395+
return s_sha3_shake_done(md, out, outlen, 0x1f, s_keccakf);
396396
}
397397

398398
#if defined LTC_TURBO_SHAKE
399399
int turbo_shake_done(hash_state *md, unsigned char *out, unsigned long outlen)
400400
{
401-
return s_sha3_shake_done(md, out, outlen, s_keccak_turbo_f);
401+
return s_sha3_shake_done(md, out, outlen, 0x1f, s_keccak_turbo_f);
402402
}
403403
#endif
404404

@@ -416,4 +416,152 @@ int sha3_shake_memory(int num, const unsigned char *in, unsigned long inlen, uns
416416
}
417417
#endif
418418

419+
#ifdef LTC_KANGAROO_TWELVE
420+
421+
static const unsigned char kangaroo_twelve_filler[] = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
422+
423+
int kangaroo_twelve_init(hash_state *md, int num)
424+
{
425+
int err;
426+
427+
LTC_ARGCHK(md != NULL);
428+
LTC_ARGCHK(num == 128 || num == 256);
429+
430+
if ((err = sha3_shake_init((hash_state*)&md->kt.outer, num)) != CRYPT_OK) return err;
431+
if ((err = sha3_shake_init((hash_state*)&md->kt.inner, num)) != CRYPT_OK) return err;
432+
md->kt.blocks_count = 0;
433+
md->kt.customization_len = 0;
434+
md->kt.remaining = 8 * 1024;
435+
md->kt.phase = 0;
436+
md->kt.finished = 0;
437+
return CRYPT_OK;
438+
}
439+
440+
static LTC_INLINE int s_kangaroo_twelve_process(hash_state *md, const unsigned char *in, unsigned long inlen)
441+
{
442+
unsigned long rem;
443+
unsigned long amount;
444+
int err;
445+
int variant;
446+
int digest_len;
447+
unsigned char digest_buf[64];
448+
449+
LTC_ARGCHK(md != NULL);
450+
LTC_ARGCHK(in != NULL || inlen == 0);
451+
452+
if (md->kt.phase == 0)
453+
{
454+
rem = md->kt.remaining;
455+
amount = rem < inlen ? rem : inlen;
456+
md->kt.remaining -= amount;
457+
if ((err = turbo_shake_process((hash_state*)&md->kt.outer, in, amount)) != CRYPT_OK) return err;
458+
in += amount;
459+
inlen -= amount;
460+
if (md->kt.remaining == 0 && inlen != 0)
461+
{
462+
md->kt.remaining = 8 * 1024;
463+
md->kt.phase = 1;
464+
md->kt.blocks_count += 1;
465+
if ((err = turbo_shake_process((hash_state*)&md->kt.outer, kangaroo_twelve_filler, sizeof(kangaroo_twelve_filler))) != CRYPT_OK) return err;
466+
}
467+
}
468+
if (md->kt.phase == 1)
469+
{
470+
do
471+
{
472+
rem = md->kt.remaining;
473+
amount = rem < inlen ? rem : inlen;
474+
md->kt.remaining -= amount;
475+
if ((err = turbo_shake_process((hash_state*)&md->kt.inner, in, amount)) != CRYPT_OK) return err;
476+
in += amount;
477+
inlen -= amount;
478+
if (md->kt.remaining == 0 && inlen != 0)
479+
{
480+
md->kt.remaining = 8 * 1024;
481+
md->kt.blocks_count += 1;
482+
assert(md->kt.outer.capacity_words == 4 || md->kt.outer.capacity_words == 8);
483+
variant = md->kt.outer.capacity_words == 4 ? 128 : 256;
484+
digest_len = variant == 128 ? 32 : 64;
485+
if ((err = s_sha3_shake_done((hash_state*)&md->kt.inner, digest_buf, digest_len, 0x0b, s_keccak_turbo_f)) != CRYPT_OK) return err;
486+
if ((err = turbo_shake_init((hash_state*)&md->kt.inner, variant)) != CRYPT_OK) return err;
487+
if ((err = turbo_shake_process((hash_state*)&md->kt.outer, digest_buf, digest_len)) != CRYPT_OK) return err;
488+
}
489+
} while (inlen != 0);
490+
}
491+
return CRYPT_OK;
492+
}
493+
494+
int kangaroo_twelve_process(hash_state *md, const unsigned char *in, unsigned long inlen)
495+
{
496+
LTC_ARGCHK(md != NULL);
497+
LTC_ARGCHK(in != NULL || inlen == 0);
498+
LTC_ARGCHK(md->kt.customization_len == 0);
499+
LTC_ARGCHK(md->kt.finished == 0);
500+
501+
return s_kangaroo_twelve_process(md, in, inlen);
502+
}
503+
504+
int kangaroo_twelve_customization(hash_state *md, const unsigned char *in, unsigned long inlen)
505+
{
506+
LTC_ARGCHK(md != NULL);
507+
LTC_ARGCHK(in != NULL || inlen == 0);
508+
LTC_ARGCHK(md->kt.finished == 0);
509+
510+
md->kt.customization_len += inlen;
511+
return s_kangaroo_twelve_process(md, in, inlen);
512+
}
513+
514+
int kangaroo_twelve_done(hash_state *md, unsigned char *out, unsigned long outlen)
515+
{
516+
int couner_len;
517+
unsigned char couner_buf[sizeof(ulong64) + 1];
518+
int err;
519+
int variant;
520+
int digest_len;
521+
unsigned char digest_buf[64];
522+
unsigned char ffff[2];
523+
unsigned char domain;
524+
525+
LTC_ARGCHK(md != NULL);
526+
LTC_ARGCHK(out != NULL || outlen == 0);
527+
528+
if (md->kt.finished == 0)
529+
{
530+
md->kt.finished = 1;
531+
couner_len = 0;
532+
while (md->kt.customization_len != 0)
533+
{
534+
couner_buf[LTC_ARRAY_SIZE(couner_buf) - 1 - 1 - couner_len] = md->kt.customization_len & 0xff;
535+
md->kt.customization_len >>= 8;
536+
++couner_len;
537+
}
538+
couner_buf[LTC_ARRAY_SIZE(couner_buf) - 1] = couner_len;
539+
if ((err = s_kangaroo_twelve_process(md, &couner_buf[LTC_ARRAY_SIZE(couner_buf) - 1 - couner_len], couner_len + 1)) != CRYPT_OK) return err;
540+
if(md->kt.phase != 0)
541+
{
542+
assert(md->kt.outer.capacity_words == 4 || md->kt.outer.capacity_words == 8);
543+
variant = md->kt.outer.capacity_words == 4 ? 128 : 256;
544+
digest_len = variant == 128 ? 32 : 64;
545+
if ((err = s_sha3_shake_done((hash_state*)&md->kt.inner, digest_buf, digest_len, 0x0b, s_keccak_turbo_f)) != CRYPT_OK) return err;
546+
if ((err = turbo_shake_process((hash_state*)&md->kt.outer, digest_buf, digest_len)) != CRYPT_OK) return err;
547+
couner_len = 0;
548+
while (md->kt.blocks_count != 0)
549+
{
550+
couner_buf[LTC_ARRAY_SIZE(couner_buf) - 1 - 1 - couner_len] = md->kt.blocks_count & 0xff;
551+
md->kt.blocks_count >>= 8;
552+
++couner_len;
553+
}
554+
couner_buf[LTC_ARRAY_SIZE(couner_buf) - 1] = couner_len;
555+
if ((err = turbo_shake_process((hash_state*)&md->kt.outer, &couner_buf[LTC_ARRAY_SIZE(couner_buf) - 1 - couner_len], couner_len + 1)) != CRYPT_OK) return err;
556+
ffff[0] = 0xff;
557+
ffff[1] = 0xff;
558+
if ((err = turbo_shake_process((hash_state*)&md->kt.outer, ffff, LTC_ARRAY_SIZE(ffff))) != CRYPT_OK) return err;
559+
}
560+
}
561+
domain = md->kt.phase == 0 ? 0x07 : 0x06;
562+
return s_sha3_shake_done(md, out, outlen, domain, s_keccak_turbo_f);
563+
}
564+
565+
#endif
566+
419567
#endif

0 commit comments

Comments
 (0)