Skip to content

jedisct1/zig-kangarootwelve

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KangarooTwelve for Zig

A pure Zig implementation of the KangarooTwelve cryptographic hash function with support for both sequential and parallel processing.

About KangarooTwelve

KangarooTwelve is a fast, secure cryptographic hash function based on Keccak (SHA-3). It uses a tree-hashing mode on top of TurboSHAKE, providing both high security and excellent performance, especially on large inputs. K12 supports arbitrary-length output and optional customization strings.

This implementation follows the specification from RFC9861 and provides both KT128 (based on TurboSHAKE128) and KT256 (based on TurboSHAKE256).

Security

KangarooTwelve inherits its security foundation from over 15 years of intensive cryptanalysis of the Keccak permutation, the same primitive underlying SHA-3. This is not a new untested algorithm, but rather a performance-optimized variant of one of the most scrutinized cryptographic primitives in history.

Proven Cryptographic Foundation

Keccak underwent rigorous analysis during the SHA-3 competition (2008-2012), where it was evaluated by the world's leading cryptographers before being selected by NIST as the SHA-3 standard. The scrutiny hasn't stopped: cryptanalysts continue to study Keccak-based functions, with the most recent significant analysis published at CRYPTO 2024. After all these years of analysis, Keccak's security remains solid.

KangarooTwelve uses the Keccak-p[1600,12] permutation with 12 rounds, exactly half the 24 rounds used in SHA-3. This design choice was made by the original Keccak team themselves, who leveraged their deep understanding of the permutation's security properties. Any cryptanalysis of Keccak directly applies to understanding K12's security.

Security Strength and Margin

K12 provides 128-bit security strength, equivalent to AES-128 and SHAKE128, which is sufficient for virtually all applications. For post-quantum security, K12 achieves NIST's security level 2 when using at least 256-bit outputs.

The current state of cryptanalysis shows attacks reaching 6 rounds of the Keccak permutation, leaving K12's 12 rounds with a substantial security margin. While this margin is smaller than SHA-3's (which has 24 rounds), it reflects a deliberate engineering trade-off: K12 sacrifices some conservative margin for significantly better performance, while maintaining strong practical security.

Standardization

The KangarooTwelve draft was proposed in 2016 and underwent 8 years of public scrutiny before being standardized as RFC 9861 in 2025.

Installation

Add this package to your build.zig.zon:

.dependencies = .{
    .kangarootwelve = .{
        .url = "https://github.com/jedisct1/zig-kangarootwelve/archive/refs/tags/v0.0.4.tar.gz",
        .hash = "...",
    },
},

Then in your build.zig:

const kangarootwelve = b.dependency("kangarootwelve", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("kangarootwelve", kangarootwelve.module("kangarootwelve"));

Usage

Basic Hashing

const std = @import("std");
const kangarootwelve = @import("kangarootwelve");
const KT128 = kangarootwelve.KT128;

var output: [32]u8 = undefined;
const message = "Hello, KangarooTwelve!";

// Hash with no customization string
try KT128.hash(message, null, &output);

// Or with a customization string
try KT128.hash(message, "my-app-v1", &output);

Variable Output Length

const KT128 = kangarootwelve.KT128;

// 64-byte output
var output: [64]u8 = undefined;
try KT128.hash(message, null, &output);

// Any output length you need
var large_output: [128]u8 = undefined;
try KT128.hash(message, null, &large_output);

Parallel Hashing

For large inputs (>3-10MB depending on CPU count), parallel processing can significantly improve performance:

const KT128 = kangarootwelve.KT128;
const allocator = std.heap.page_allocator;
const large_data = try allocator.alloc(u8, 100 * 1024 * 1024); // 100MB
defer allocator.free(large_data);

var output: [32]u8 = undefined;
try KT128.hashParallel(large_data, null, &output, allocator);

The implementation automatically adjusts the threshold for parallel processing based on CPU count (3MB for 8+ cores, 5MB for 4-7 cores, 10MB for 1-3 cores).

Using KT256

const KT256 = kangarootwelve.KT256;
var output: [64]u8 = undefined;
try KT256.hash(message, null, &output);

API

KT128

A struct providing KangarooTwelve with 128-bit security based on TurboSHAKE128.

hash(message: []const u8, customization: ?[]const u8, out: []u8) !void

Hashes a message using sequential processing with SIMD optimizations.

  • message: Input data to hash
  • customization: Optional customization string (can be null)
  • out: Output buffer of any length

hashParallel(message: []const u8, customization: ?[]const u8, out: []u8, allocator: std.mem.Allocator) !void

Hashes a message with parallel chunk processing. Automatically uses sequential processing for smaller inputs to avoid thread pool overhead.

  • message: Input data to hash
  • customization: Optional customization string (can be null)
  • out: Output buffer of any length
  • allocator: Memory allocator for thread pool and intermediate buffers

KT256

Same API as KT128, but uses TurboSHAKE256 internally for 256-bit security.

Performance

The implementation includes optimizations for both small and large inputs:

  • Small inputs (≤8KB): Single-pass processing with no chunking overhead
  • Medium inputs (8KB - ~10MB): Sequential chunked processing with SIMD acceleration
  • Large inputs (>~3-10MB depending on CPU count): Parallel processing with dynamic thread pool sizing

Benchmark your specific use case with:

zig build bench

This runs benchmarks on various input sizes and compares sequential vs parallel performance.

Building and Testing

Build the library:

zig build

Run tests:

zig build test

Run benchmarks:

zig build bench

Build with optimizations:

zig build -Doptimize=ReleaseFast

Benchmarks

zig run -O ReleaseFast --zig-lib-dir lib lib/std/crypto/benchmark.zig

Apple M3

           sha256:       3209 MiB/s
           blake3:       2124 MiB/s
            kt128:       3548 MiB/s
  blake3-parallel:      10538 MiB/s
   kt128-parallel:      13619 MiB/s

AMD Zen 4

          sha256:       1547 MiB/s
           kt128:       4452 MiB/s
          blake3:       5013 MiB/s
 blake3-parallel:      15664 MiB/s
  kt128-parallel:      27498 MiB/s

Packages

 
 
 

Contributors

Languages