# Improving the fastest pure-Julia cryptographic hash!

**URL:** https://discourse.julialang.org/t/improving-the-fastest-pure-julia-cryptographic-hash/104386
**Category:** Performance
**Created:** [September 29, 2023, 11:28am UTC](https://discourse.julialang.org/t/improving-the-fastest-pure-julia-cryptographic-hash/104386 "2023-09-29T11:28:55Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)
#### Post date: [September 29, 2023, 11:28am UTC](https://discourse.julialang.org/t/improving-the-fastest-pure-julia-cryptographic-hash/104386/1 "2023-09-29T11:28:55Z")

</div>

Hi All!

For another project of mine, I wanted a good fast hash that wasn’t trivial to mock. After an excessive amount of investigation, I’ve settled on KangarooTwelve. To quote the project readme, I think it strikes a really nice balance between:

- Simplicity (Keccak + sponge + hopping)
- Security (128-bit, sharing the same cryptographic base as SHA3)
- Speed (up to ~2bytes/cycle, with AVX512)

> **[GitHub - tecosaur/KangarooTwelve.jl: WIP](https://github.com/tecosaur/KangarooTwelve.jl/)**
>
> WIP. Contribute to tecosaur/KangarooTwelve.jl development by creating an account on GitHub.

With a little help from @Lilith, @Sukera, and @Oscar_Smith (big thanks for the help so far 🤩) in `#performance-helpdesk` we’ve currently got what seems to be _the fastest pure-julia cryptographic hash_ (by some margin).

```julia
julia> KangarooTwelve.throughput(:crc32c)
 crc32c throughput: ~30546 MiB/s

julia> KangarooTwelve.throughput(:md5)
 md5 throughput: ~1037 MiB/s

julia> KangarooTwelve.throughput(:sha1)
 sha1 throughput: ~653 MiB/s

julia> KangarooTwelve.throughput(:sha256)
 sha256 throughput: ~431 MiB/s

julia> KangarooTwelve.throughput(:sha3_256)
 sha3_256 throughput: ~210 MiB/s

julia> KangarooTwelve.throughput(:k12)
 KangarooTwelve (singlethreaded) throughput: ~1630 MiB/s

```

That said, it seems that we’re quite some way from where we could be. By my estimation, this is currently around **~4** cycles per byte, and [according to the keccak team](https://keccak.team/kangarootwelve.html) **1.4** cycles/byte is achievable with AVX2 and **0.5** cycles/byte with AVX512.

So, that’s a **~3-8x** performance improvement to be had, and that’s not even considering threading (yes, this can be threaded).

I’m pretty sure I’m nearing the limit of my high-performance/micro-optimisation abilities though, and I’d love it if I might be able to interest some of the more performance/optimisation-minded folks around here to take a look and see how far we can push this!

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [September 29, 2023, 11:45am UTC](https://discourse.julialang.org/t/improving-the-fastest-pure-julia-cryptographic-hash/104386/2 "2023-09-29T11:45:20Z")

</div>

This is 🔥, but FTR AFAIK (not an expert) K12 may be kind of obsoleted (from performance and flexibility perspectives) by newer designs. One of the most awesome things about sponge-based/permutation-based crypto is how it enables implementing the entirety of symmetric crypto with most of the code shared between the “primitives”, something that K12 is not designed for as far as I remember (it’s just a hash I think, at least “officially”).

For example, Ascon is the winner of the Lightweight Cryptography challenge (by the US NIST):

> **[Ascon (cipher)](https://en.wikipedia.org/wiki/Ascon_(cipher))**
>
> Ascon is a family of lightweight authenticated ciphers that had been selected by US National Institute of Standards and Technology (NIST) for future standardization of the lightweight cryptography.
> Ascon was developed in 2014 by a team of researchers from Graz University of Technology, Infineon Technologies, Lamarr Security Research, and Radboud University. The cipher family was chosen as a finalist of the CAESAR Competition in February 2019.
> NIST had announced its decision on February 7, 2023 ...

Other finalists:

> **[Finalists - Lightweight Cryptography | CSRC | CSRC](https://csrc.nist.gov/Projects/lightweight-cryptography/finalists)**
>
> The following table lists the ten Finalists of the lightweight crypto standardization process. Official comments on the Finalists should be submitted using the 'Submit Comment' link for the appropriate algorithm. Comments from the lwc-forum...

Furthermore, the Keccak Team themselves (after some iteration, including third-party work) introduced several new concepts that make sponges obsolete AFAIK, such as deck functions and Farfalle. These are not just new algorithms, but seem like they will change the way symmetric crypto is both implemented and used (new modes) for the better: [Keccak Team](https://keccak.team/2022/refactoring_with_deck_functions.html)

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [September 29, 2023, 11:50am UTC](https://discourse.julialang.org/t/improving-the-fastest-pure-julia-cryptographic-hash/104386/3 "2023-09-29T11:50:35Z")

</div>

> [@tecosaur](#):
>
> high-performance/micro-optimisation

One interesting thing about implementing crypto primitives is that, AFAIK, safety from some side-channel attacks requires using assembly (or `llvmcall`, in the case of Julia, I guess). For example, ensuring that some operations are constant-time (to protect against timing attacks) as necessary sometimes requires protection from an overzealous compiler optimizer. I wonder whether there are any existing Julia projects that tackle such issues?

---

<div class="post-metadata">

### Author: ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)
#### Post date: [September 29, 2023, 12:17pm UTC](https://discourse.julialang.org/t/improving-the-fastest-pure-julia-cryptographic-hash/104386/4 "2023-09-29T12:17:20Z")

</div>

> [@nsajko](#):
>
> K12 may be kind of obsoleted (from performance and flexibility perspectives) by newer designs

AFAIK the current “fastest” established general-purpose cryptographic hash is Blake3. However, at longer input lengths (what I care abount more), K12 is actually extremely competitive. To take an excerpt from the Blake3 paper:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/8/c8a77dcf36858afd0beaf253f1fbf009f060d72b.png)

> [@nsajko](#):
>
> One of the most awesome things about sponge-based/permutation-based crypto … something that K12 is not designed for as far as I remember

K12 _is_ a [sponge](https://keccak.team/sponge_duplex.html) + [permutation](https://keccak.team/keccakp.html) 🙃.

> [@nsajko](#):
>
> Furthermore, the Keccak Team themselves (after some iteration, including third-party work) introduced several new concepts that make sponges obsolete AFAIK, such as deck functions and Farfalle. These are not just new algorithms, but seem like they will change the way symmetric crypto is both implemented and used (new modes) for the better

I have seen 🙂 however, those are all authenticated encryption schemes, and AFAIK no established desk/farfalle based hash function currently exists.

> [@nsajko](#):
>
> One interesting thing about implementing crypto primitives is that, AFAIK, safety from some side-channel attacks requires using assembly (or `llvmcall`, in the case of Julia, I guess). For example, ensuring that some operations are constant-time (to protect against timing attacks) as necessary sometimes requires protection from an overzealous compiler optimizer.

My understanding is that this is much more relevant when looking at crypto that involves secrets (e.g. encryption). When hashing, an attacker knows _everything_ to start with … which is a large part of why translating a cipher to a hash is non-trivial (the secret is no longer secret).

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [March 8, 2026, 11:08pm UTC](https://discourse.julialang.org/t/improving-the-fastest-pure-julia-cryptographic-hash/104386/5 "2026-03-08T23:08:59Z")

</div>

Have you looked into optimizing the Keccak permutation by applying the _lane complementing transform_? The transform is applied either to each round or to the entire permutation, and is meant to speed up, depending on the platform, the χ (nonlinear) step of the round function by eliminating some bit complement operations by applying De Morgan’s laws.

Described in the Keccak implementation overview:

- [https://keccak.team/files/Keccak-implementation-3.2.pdf](https://keccak.team/files/Keccak-implementation-3.2.pdf)
