A lightweight, portable C library implementing ChaCha20, XChaCha20, ChaCha20-Poly1305, XChaCha20-Poly1305, IETF & Bernstein variants, N rounds, BLAKE2s/b, BLAKE3.
The library is optimized for code size while matching or beating throughput of comparable crypto libraries at -O3. For reference, ChaCha20-Poly1305 compiles to just 2.2KB at -Os and ~5.1KB at -O3 on Windows.
Features can be toggled in ccs_config.h.
| Category | Feature |
|---|---|
| Stream Ciphers | IETF ChaCha20 (96-bit nonce, 32-bit counter) [1] |
| D.J. Bernstein ChaCha20 (64-bit nonce, 64-bit counter) [2] | |
| XChaCha20 (192-bit nonce, 64-bit counter) [3] | |
| AEAD Modes | IETF ChaCha20-Poly1305 [1] |
| D.J. Bernstein ChaCha20-Poly1305 [4] (compatible with LibSodium) | |
| XChaCha20-Poly1305 [3], [4] | |
| One Time Authenticators | Poly1305 [1] |
| Hash Functions | BLAKE2s [5] |
| BLAKE2b [5] | |
| BLAKE3 [6] |
All (X)ChaCha and (X)ChaCha-Poly1305 functions support custom number of rounds through their ChaChaN APIs, allowing for ChaCha12 or ChaCha8. ChaChaN supports custom counter start.
- Add this project using
add_subdirectory(path/to/ChaChaSlide)(CMake 3.16+, GCC/Clang). - Link your application to either
ccs-sizeorccs-speedusingtarget_link_libraries(). - Configure
include/ccs_config.hfor the features you want to keep. - See
/examplefor usage.
1 Tests and benchmarks are off by default. Enable BUILD_TESTING for tests or BUILD_BENCHMARKS for the benchmark runner.
2 Library level LTO is enabled when supported. Set CMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF to disable it.
Details
Set CCS_B3_MAX in include/ccs_config.h to choose the maximum message size BLAKE3 can hash: 2^CCS_B3_MAX bytes. This determines the size of ccs_blake3_ctx_t. The default is 64.
CCS_B3_MAX |
Maximum message size | sizeof(ccs_blake3_ctx_t) |
|---|---|---|
| 32 | 2^32 bytes (4 GiB) | 844 bytes |
| 40 | 2^40 bytes (1 TiB) | 1,100 bytes |
| 48 | 2^48 bytes (256 TiB) | 1,356 bytes |
| 56 | 2^56 bytes (64 PiB) | 1,612 bytes |
| 64 | 2^64 bytes (16 EiB) | 1,868 bytes |
Bytes per feature, including dependencies. Rows are not additive due to feature overlap.1
| Feature | -Os | -O3 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Windows x86-64 | Linux x86-64 | Cortex-M0+2 | Cortex-M32 | AArch64 | AVR ATmega328P2 | Windows x86-64 | Linux x86-64 | Cortex-M0+2 | Cortex-M32 | AArch64 | AVR ATmega328P2 | |
| ChaCha20 IETF | 560 | 504 | 516 | 464 | 628 | 1,518 | 1,712 | 1,459 | 1,568 | 1,304 | 1,548 | 5,756 |
| ChaCha20 DJB | 544 | 495 | 516 | 476 | 612 | 1,768 | 1,712 | 1,555 | 1,576 | 1,292 | 1,488 | 6,204 |
| XChaCha20 | 784 | 766 | 764 | 676 | 868 | 2,242 | 2,512 | 2,323 | 2,340 | 1,980 | 2,320 | 10,180 |
| ChaCha20-Poly1305 IETF | 2,176 | 1,957 | 2,176 | 1,824 | 2,184 | 4,056 | 5,072 | 4,798 | 5,624 | 4,268 | 4,200 | 15,266 |
| ChaCha20-Poly1305 DJB | 2,064 | 1,834 | 2,144 | 1,792 | 2,104 | 4,100 | 4,976 | 4,478 | 5,516 | 4,260 | 3,992 | 15,178 |
| XChaCha20-Poly1305 | 2,416 | 2,214 | 2,492 | 2,064 | 2,500 | 4,628 | 5,744 | 5,598 | 6,796 | 4,980 | 5,052 | 19,586 |
| Poly1305 | 1,024 | 883 | 1,262 | 898 | 1,004 | 1,852 | 2,736 | 2,335 | 3,440 | 2,672 | 2,020 | 7,862 |
| BLAKE2s | 1,152 | 1,067 | 1,042 | 848 | 1,236 | 2,030 | 5,440 | 5,593 | 6,372 | 5,356 | 5,820 | 26,868 |
| BLAKE2b | 1,312 | 1,220 | 1,526 | 1,276 | 1,324 | 3,772 | 7,248 | 7,321 | 22,456 | 16,976 | 6,952 | -3 |
| BLAKE34 | 1,920 | 1,862 | 1,528 | 1,374 | 1,932 | 3,528 | 6,368 | 6,546 | 7,044 | 5,356 | 6,040 | 25,500 |
| HChaCha20 | 496 | 434 | 460 | 416 | 556 | 1,238 | 704 | 666 | 1,016 | 712 | 836 | 3,582 |
| Default suite5 | 8,160 | 7,712 | 7,480 | 6,444 | 8,540 | 16,268 | 28,512 | 28,286 | 45,680 | 35,220 | 27,516 | 231,2503 |
1 Full-API linked code, constants, and initialized data. Excludes runtime startup, RAM, and debug metadata. GCC 16.1 (Windows), 13.4 (Cortex-M), 14.2 (others). Uses LTO within the library.
2 CCS_POLY=2 on Cortex-M, 3 on AVR, 1 elsewhere.
3 Exceeds the ATmega328P's 32 KiB flash.
4 BLAKE3 includes hash, keyed hash, KDF, and XOF.
5 Default suite includes all features.
Windows 11 x86-64. GCC 16.1. LTO. MiB/s.
| Operation | 1 MiB | 64 KiB | 1 KiB | 16 B | ||||
|---|---|---|---|---|---|---|---|---|
| -O3 | -Os | -O3 | -Os | -O3 | -Os | -O3 | -Os | |
| ChaCha20 IETF | 1,244.1 | 474.1 | 1,244.3 | 473.8 | 1,154.3 | 450.4 | 137.2 | 79.1 |
| ChaCha20 DJB | 1,238.6 | 473.1 | 1,239.0 | 472.7 | 1,140.8 | 450.2 | 136.2 | 78.6 |
| XChaCha20 | 1,238.4 | 472.9 | 1,238.7 | 469.7 | 1,061.5 | 422.0 | 86.0 | 45.3 |
| ChaCha20-Poly1305 encrypt | 926.0 | 414.5 | 925.7 | 413.5 | 798.5 | 360.9 | 70.7 | 36.5 |
| ChaCha20-Poly1305 DJB encrypt | 924.1 | 412.6 | 922.9 | 410.2 | 790.7 | 359.7 | 68.9 | 36.6 |
| XChaCha20-Poly1305 encrypt | 924.0 | 414.0 | 922.1 | 411.9 | 756.4 | 345.1 | 53.7 | 27.5 |
| Poly1305 | 3,625.0 | 3,318.4 | 3,615.4 | 3,315.8 | 2,915.1 | 2,491.2 | 221.0 | 161.2 |
| BLAKE2s-256 | 1,026.9 | 408.4 | 1,023.4 | 409.0 | 938.1 | 388.6 | 108.3 | 57.2 |
| BLAKE2b-512 | 1,739.2 | 665.7 | 1,734.9 | 666.1 | 1,365.8 | 573.8 | 82.5 | 39.1 |
| BLAKE3-256 | 1,289.2 | 514.5 | 1,290.6 | 515.1 | 1,188.0 | 501.6 | 101.6 | 52.2 |
Inexpensive barebones ARM Cortex-M0+ microcontroller.
Pending
Legacy 8-bit Microcontroller on an Arduino Uno.
Pending
Monocypher 4.0.3 · libsodium 1.0.22 · wolfCrypt 5.9.4.
Handwritten SIMD/assembly backends disabled for raw portable comparison.
Windows 11 x86-64. GCC 16.1. LTO. MiB/s.
Added bytes when statically linked, excluding the common baseline.1
| Requested operations | -Os | -O3 | ||||||
|---|---|---|---|---|---|---|---|---|
| CCS | Monocypher | libsodium | wolfCrypt | CCS | Monocypher | libsodium | wolfCrypt | |
| ChaCha20 IETF | 464 | 1,356 | 3,168 | 1,172 | 1,540 | 3,920 | 4,576 | 3,940 |
| ChaCha20 DJB | 448 | 1,288 | 3,184 | - | 1,636 | 3,856 | 4,576 | - |
| XChaCha20 | 672 | 1,528 | 3,728 | 2,140 | 2,372 | 4,176 | 5,120 | 6,820 |
| ChaCha20-Poly1305 IETF | 2,196 | 3,436 | 5,836 | 4,000 | 5,036 | 7,652 | 10,644 | 11,528 |
| ChaCha20-Poly1305 DJB | 2,084 | - | 5,660 | - | 4,976 | - | 10,468 | - |
| XChaCha20-Poly1305 | 2,456 | 3,480 | 6,412 | 4,964 | 5,876 | 7,896 | 11,348 | 12,620 |
| Poly1305 | 880 | 1,068 | 2,976 | 1,480 | 2,376 | 1,720 | 6,080 | 2,552 |
| BLAKE2s | 1,288 | - | - | 8,016 | 6,552 | - | - | 14,304 |
| BLAKE2b | 1,424 | 6,876 | 8,416 | 10,104 | 8,504 | 8,776 | 9,504 | 12,632 |
| BLAKE3 | 1,868 | - | - | - | 5,468 | - | - | - |
| Common suite2 | 3,804 | 10,468 | 13,020 | 14,356 | 13,824 | 16,852 | 18,520 | 23,644 |
"-" = Unsupported
1 AEAD includes encrypt/decrypt; BLAKE2 and BLAKE3 include keyed/unkeyed hashing.
2 Common suite: IETF ChaCha20, IETF AEAD, Poly1305, and BLAKE2b.
Handwritten SIMD and assembly disabled for raw comparison. Includes key setup and finalization. AEAD uses empty AD.
Notably, CCS performs secret zeroing, the others do not.
| Operation | 1 MiB | 64 KiB | 16 B | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CCS | Monocypher | libsodium | wolfCrypt | CCS | Monocypher | libsodium | wolfCrypt | CCS | Monocypher | libsodium | wolfCrypt | |
| ChaCha20 IETF | 472.7 | 937.1 | 1,168.6 | 989.9 | 471.7 | 956.1 | 1,175.6 | 1,002.6 | 108.9 | 131.8 | 196.7 | 227.0 |
| ChaCha20 DJB | 471.9 | 942.3 | 1,171.4 | - | 469.9 | 956.8 | 1,177.7 | - | 108.6 | 131.5 | 198.1 | - |
| XChaCha20 | 472.3 | 932.0 | 1,171.3 | 982.5 | 466.8 | 954.0 | 1,176.2 | 997.3 | 53.4 | 75.8 | 121.8 | 73.6 |
| ChaCha20-Poly1305 encrypt | 412.8 | 729.6 | 868.7 | 760.4 | 409.0 | 740.2 | 876.3 | 762.8 | 42.5 | 53.2 | 58.4 | 61.8 |
| ChaCha20-Poly1305 decrypt | 413.0 | 723.9 | 870.6 | 757.6 | 409.2 | 737.6 | 875.3 | 762.3 | 41.7 | 51.0 | 53.5 | 59.9 |
| ChaCha20-Poly1305 DJB encrypt | 413.1 | - | 871.6 | - | 408.7 | - | 876.6 | - | 41.3 | - | 56.9 | - |
| ChaCha20-Poly1305 DJB decrypt | 412.7 | - | 872.6 | - | 408.3 | - | 873.7 | - | 40.7 | - | 53.9 | - |
| XChaCha20-Poly1305 encrypt | 413.2 | 736.4 | 867.2 | 761.4 | 408.5 | 739.1 | 874.4 | 768.3 | 30.6 | 41.4 | 48.6 | 34.6 |
| XChaCha20-Poly1305 decrypt | 412.6 | 732.4 | 873.1 | 763.1 | 408.5 | 736.9 | 875.8 | 770.0 | 30.3 | 39.9 | 45.0 | 33.9 |
| Poly1305 | 3,301.2 | 3,289.5 | 3,445.5 | 3,200.1 | 3,299.7 | 3,299.2 | 3,443.1 | 3,234.8 | 383.5 | 421.2 | 524.4 | 882.9 |
| BLAKE2s-256 | 408.4 | - | - | 632.9 | 408.6 | - | - | 644.9 | 70.8 | - | - | 119.8 |
| BLAKE2s-256 keyed | 408.0 | - | - | 638.3 | 408.5 | - | - | 644.6 | 41.9 | - | - | 64.8 |
| BLAKE2b-512 | 665.4 | 1,273.9 | 1,387.9 | 1,003.6 | 664.8 | 1,292.4 | 1,443.5 | 1,034.1 | 44.2 | 93.6 | 91.2 | 96.7 |
| BLAKE2b-512 keyed | 665.7 | 1,272.4 | 1,395.5 | 999.7 | 662.7 | 1,287.0 | 1,435.8 | 1,031.3 | 28.6 | 51.1 | 53.9 | 49.9 |
| BLAKE3-256 | 515.0 | - | - | - | 514.8 | - | - | - | 65.7 | - | - | - |
| BLAKE3-256 keyed | 515.3 | - | - | - | 515.8 | - | - | - | 65.5 | - | - | - |
| Operation | 1 MiB | 64 KiB | 16 B | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CCS | Monocypher | libsodium | wolfCrypt | CCS | Monocypher | libsodium | wolfCrypt | CCS | Monocypher | libsodium | wolfCrypt | |
| ChaCha20 IETF | 1,243.5 | 1,165.5 | 1,206.3 | 1,132.5 | 1,243.9 | 1,198.4 | 1,226.5 | 1,142.4 | 231.3 | 198.5 | 222.7 | 238.9 |
| ChaCha20 DJB | 1,234.5 | 1,182.3 | 1,216.4 | - | 1,240.4 | 1,199.7 | 1,224.9 | - | 231.8 | 199.9 | 225.5 | - |
| XChaCha20 | 1,237.6 | 1,171.5 | 1,219.9 | 1,108.6 | 1,238.3 | 1,197.6 | 1,224.4 | 1,141.4 | 115.1 | 109.2 | 128.6 | 118.9 |
| ChaCha20-Poly1305 encrypt | 925.7 | 893.5 | 902.5 | 853.5 | 925.8 | 899.0 | 903.9 | 861.0 | 89.8 | 87.6 | 61.3 | 95.1 |
| ChaCha20-Poly1305 decrypt | 925.3 | 888.1 | 885.7 | 849.2 | 926.3 | 899.0 | 903.6 | 860.8 | 90.2 | 86.3 | 57.1 | 91.8 |
| ChaCha20-Poly1305 DJB encrypt | 921.0 | - | 904.5 | - | 922.6 | - | 902.5 | - | 86.0 | - | 61.8 | - |
| ChaCha20-Poly1305 DJB decrypt | 918.5 | - | 901.3 | - | 923.6 | - | 902.8 | - | 86.0 | - | 56.3 | - |
| XChaCha20-Poly1305 encrypt | 923.6 | 893.3 | 903.5 | 848.1 | 922.5 | 898.1 | 903.4 | 859.0 | 64.3 | 63.4 | 49.1 | 55.0 |
| XChaCha20-Poly1305 decrypt | 923.3 | 890.5 | 900.9 | 852.6 | 922.0 | 898.2 | 900.8 | 858.7 | 63.9 | 61.8 | 47.0 | 54.0 |
| Poly1305 | 3,628.6 | 3,599.9 | 3,459.8 | 3,463.1 | 3,624.9 | 3,604.5 | 3,470.6 | 3,506.2 | 640.6 | 845.3 | 532.1 | 1,066.6 |
| BLAKE2s-256 | 1,038.2 | - | - | 1,056.0 | 1,039.4 | - | - | 1,136.6 | 173.7 | - | - | 209.7 |
| BLAKE2s-256 keyed | 1,038.3 | - | - | 1,120.6 | 1,038.9 | - | - | 1,134.2 | 101.7 | - | - | 100.1 |
| BLAKE2b-512 | 1,735.6 | 1,886.0 | 1,734.6 | 1,131.6 | 1,737.4 | 1,897.7 | 1,742.2 | 1,155.0 | 120.8 | 168.7 | 99.4 | 123.0 |
| BLAKE2b-512 keyed | 1,736.5 | 1,872.9 | 1,735.4 | 1,139.8 | 1,735.5 | 1,894.5 | 1,735.9 | 1,155.1 | 77.1 | 91.6 | 61.3 | 60.5 |
| BLAKE3-256 | 1,289.5 | - | - | - | 1,285.7 | - | - | - | 146.8 | - | - | - |
| BLAKE3-256 keyed | 1,292.1 | - | - | - | 1,291.1 | - | - | - | 147.2 | - | - | - |
"-" = Unsupported
ChaChaSlide is not formally audited. Its implementations are validated against a large set of test vectors. All functions are constant time (on tested platforms with GCC), with the exception of Poly1305, which depends on the selected multiply implementation and CPU architecture (read below). While custom round counts are supported, this is intended for ChaCha8 and ChaCha12, which have been the subject of cryptanalysis. Using custom rounds is an experiment that this library supports.
About Constant Time Poly1305
Poly1305 relies on a 32->64 multiply, which may not be constant time in hardware or are implemented with variable time software helpers depending on the CPU architecture. This may expose Poly1305 to a side channel timing attacks.ChaChaSlide has 3 implementations of the Poly1305 multiply to select, which will compile to constant time code depending on the platform and implementation used. Performance will be reduced.
Select CCS_POLY in include/ccs_config.h:
- 0: Off Poly1305 is not exposed. However, using AEAD modes (ChaCha20-Poly1305) will default to the Generic implementation.
- 1: Generic: Normal multiplication. Fastest choice on all platforms. Use on platforms that have constant time 32->64 multipliers.
- 2: 32->32: Forces 15-bit multiplies and will work on platforms with 32->32 multipliers. Best for inexpensive ARM Cortex-M microcontrollers (M0/M0+/M3).
- 3: 8-bit: Optimized for 8-bit architectures with 16-bit accumulators. E.g. AVR, PIC.
| Platform | Recommended CCS_POLY selection |
|---|---|
| Modern x86-64 | 1 |
| Cortex-M0/M0+/M1/M3/M23 | 2 |
| Cortex-M4/M7 | 1 |
| Other Cortex and AArch64 | 1 or 2 |
| AVR with hardware multiply | 3 |
| PIC18 | 3 |
| Other without hardware multiply | Conditional |
| RISC-V | Conditional |
Monocypher, wolfCrypt and LibSodium do not guarantee constant time Poly1305 if the CPU does not have a constant time multiplier. The reduced speed of a constant time ChaChaSlide implementation is not directly comparable to a non constant time benchmark of a comparable library due to the potential side channel vulnerability.
- Can we go smaller: Yes! We can also go substantially faster at -Os at the cost of code size. ChaChaSlide also prevents some footguns (e.g. allowing ChaCha counter overflow).
- Can we go faster: A little bit. ChaChaSlide pushes the limits on my hardware, and the speedups are architecture dependant (e.g. taking advantage of 64-bit operations), and might displace code designed for -Os (e.g. loop unrolling and array-less computation).
- Why not create two sources for size and speed optimized code: This is on the table, but one codebase keeps the project simpler.
- Why include BLAKE2/3: BLAKE is based on the core ChaCha ARX function and is compact. This is the ChaCha"Slide".
- Is the project finished: The library is fully functional.
[1] Y. Nir and A. Langley, “ChaCha20 and Poly1305 for IETF protocols,” RFC 8439, Jun. 2018, doi: 10.17487/RFC8439.
[2] D. J. Bernstein, “ChaCha, a variant of Salsa20,” Jan. 28, 2008. [Online]. Available: https://cr.yp.to/chacha/chacha-20080128.pdf
[3] S. Arciszewski, “XChaCha: eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305,” Internet-Draft draft-irtf-cfrg-xchacha-03, Jan. 2020, expired. [Online]. Available: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03
[4] The libsodium Project, “ChaCha20-Poly1305,” The Sodium Crypto Library. Accessed: Nov. 4, 2026. [Online]. Available: https://doc.libsodium.org/secret-key_cryptography/aead/chacha20-poly1305
[5] M.-J. O. Saarinen and J.-P. Aumasson, “The BLAKE2 cryptographic hash and message authentication code (MAC),” RFC 7693, Nov. 2015, doi: 10.17487/RFC7693.
[6] J. O’Connor, J.-P. Aumasson, S. Neves, and Z. Wilcox-O’Hearn, “BLAKE3: one function, fast everywhere,” 2020. [Online]. Available: https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf
1.0.1 Add BLAKE3. BLAKE2 speed improvements.
1.0.0 Initial Release