all repos — TinyCrypT @ 7d1a1493a6ed478d3d2ac234ad7ed9b22a0ce1e5

Short and sweet classical cryptographic primitives

32-bit fixes and switched to Zig CC as default compiler
Juniper Beatitudes [email protected]
Sat, 25 Jul 2026 12:29:21 -0500
commit

7d1a1493a6ed478d3d2ac234ad7ed9b22a0ce1e5

parent

b2074322e2415a2728d0b4b287f210a31929632f

D demeter-machine.txt

@@ -1,12 +0,0 @@

-[binaries] -c = 'mips64el-unknown-linux-gnuabin32-gcc' -cpp = 'mips64el-unknown-linux-gnuabin32-g++' -ar = 'mips64el-unknown-linux-gnuabin32-ar' -windres = 'mips64el-unknown-linux-gnuabin32-windres' -strip = 'mips64el-unknown-linux-gnuabin32-strip' - -[host_machine] -system = 'linux' -cpu_family = 'mips64' -cpu = 'mips64' -endian = 'little'
M flake.lockflake.lock

@@ -1,93 +1,24 @@

{ "nodes": { - "esp32-overlay": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" - }, - "locked": { - "lastModified": 1767146219, - "narHash": "sha256-dviXadLLdKhoW9apdBoF+UpGxgcukSin6h6oaxKY/w4=", - "owner": "mirrexagon", - "repo": "nixpkgs-esp-dev", - "rev": "a202c3c73bed7e2cb8c6870f80781993dab41fcd", - "type": "github" - }, - "original": { - "owner": "mirrexagon", - "repo": "nixpkgs-esp-dev", - "type": "github" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1758070117, - "narHash": "sha256-uLwwHFCZnT1c3N3biVe/0hCkag2GSrf9+M56+Okf+WY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e9b7f2ff62b35f711568b1f0866243c7c302028d", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-25.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1767047869, - "narHash": "sha256-tzYsEzXEVa7op1LTnrLSiPGrcCY6948iD0EcNLWcmzo=", + "lastModified": 1784707089, + "narHash": "sha256-2V/6imsUgB7mPZlHY54oeVBRDoZbPKnvzwkAHUSSufk=", "owner": "nixos", "repo": "nixpkgs", - "rev": "89dbf01df72eb5ebe3b24a86334b12c27d68016a", + "rev": "b3fe9581c9061c749abef42b6d4ee7b7c05c33fa", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-25.11", + "ref": "nixos-26.05", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { - "esp32-overlay": "esp32-overlay", - "nixpkgs": "nixpkgs_2" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" + "nixpkgs": "nixpkgs" } } },
M flake.nixflake.nix

@@ -2,25 +2,18 @@ {

description = "TinyCrypT Build Environment"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.11"; - esp32-overlay.url = "github:mirrexagon/nixpkgs-esp-dev"; + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-26.05"; }; outputs = { self, nixpkgs, - esp32-overlay, ... }@inputs: let system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; - pkgs-persephone = import nixpkgs { - overlays = [ esp32-overlay.overlays.default ]; - inherit system; - config.permittedInsecurePackages = [ "python3.13-ecdsa-0.19.1" ]; - }; aphrodite_shl = pkgs.mkShell { name = "tct-tooling-env-aphrodite"; packages = with pkgs; [

@@ -32,52 +25,14 @@ valgrind

bear tokei cbmc - ]; - }; - teiresia_shl = pkgs.mkShell { - name = "tct-tooling-env-teiresia"; - packages = with pkgs; [ - ninja - meson - pkgsCross.aarch64-multiplatform-musl.gcc - clang-tools - valgrind - bear - tokei - ]; - }; - demeter_shl = pkgs.mkShell { - name = "tct-tooling-env-demeter"; - packages = with pkgs; [ - ninja - meson - pkgsCross.mips64el-linux-gnuabin32.gcc - clang-tools - valgrind - bear - tokei - ]; - }; - persephone_shl = pkgs.mkShell { - name = "tct-tooling-env-persephone"; - packages = with pkgs-persephone; [ - ninja - meson - esp-idf-xtensa - qemu-esp32 - clang-tools - valgrind - bear - tokei + zig_0_16 + jq ]; }; in { devShells.${system} = { default = aphrodite_shl; - teiresia = teiresia_shl; - demeter = demeter_shl; - persephone = persephone_shl; }; }; }
A machines/aphrodite.ini

@@ -0,0 +1,7 @@

+[binaries] +c = ['zig', 'cc'] +cpp = ['zig', 'c++'] +ar = ['zig', 'ar'] +ranlib = ['zig', 'ranlib'] +lib = ['zig', 'lib'] +dlltool = ['zig', 'dlltool']
M meson.buildmeson.build

@@ -3,115 +3,124 @@

incdir = include_directories('.') sources = [ - 'tinycrypt/portable/kangarootwelve128.c', - 'tinycrypt/portable/sha2.c', + 'tinycrypt/portable/kangarootwelve128.c', + 'tinycrypt/portable/sha2.c', + 'tinycrypt/portable/chacha20.c', ] if meson.get_compiler('c').has_define('__SIZEOF_INT128__') - sources += 'tinycrypt/x86_64_aarch64/ed25519.c' + sources += 'tinycrypt/min64/ed25519.c' else - sources += 'tinycrypt/portable/ed25519.c' + sources += 'tinycrypt/min32/ed25519.c' endif if meson.get_compiler('c').has_define('__SIZEOF_INT128__') - sources += 'tinycrypt/x86_64_aarch64/chacha20_poly1305.c' + sources += 'tinycrypt/min64/chacha20_poly1305.c' else - sources += 'tinycrypt/portable/chacha20_poly1305.c' + sources += 'tinycrypt/min32/chacha20_poly1305.c' endif if meson.get_compiler('c').has_define('__SIZEOF_INT128__') - sources += 'tinycrypt/x86_64_aarch64/x25519.c' + sources += 'tinycrypt/min64/x25519.c' else - sources += 'tinycrypt/portable/x25519.c' + sources += 'tinycrypt/min32/x25519.c' endif build_args = [ - '-O3', - '-ffreestanding', + '-O3', + '-ffreestanding', ] if target_machine.cpu_family() == 'x86_64' - build_args += '-march=native' + build_args += '-march=native' + build_args += '-DTCT_SIMD128' + build_args += '-DTCT_SIMD256' +endif + +if target_machine.cpu_family() == 'aarch64' + build_args += '-DTCT_SIMD128' + build_args += '-DTCT_SIMD256' +endif + +if target_machine.endian() == 'little' + build_args += '-DTCT_LITTLE_ENDIAN' endif target = static_library('tinycrypt', sources, c_args: build_args, include_directories: incdir) -project_dep = declare_dependency( - include_directories: incdir, - link_with : target -) +project_dep = declare_dependency(include_directories: incdir, link_with: target) set_variable(meson.project_name() + '_dep', project_dep) sha2_test_sources = [ - 'tests/src/sha2/SHA512LongMsg.cpp', - 'tests/src/sha2/SHA512ShortMsg.cpp', - 'tests/src/sha2/SHA512Monte.cpp', - 'tests/src/sha2/SHA256LongMsg.cpp', - 'tests/src/sha2/SHA256ShortMsg.cpp', - 'tests/src/sha2/SHA256Monte.cpp', + 'tests/src/sha2/SHA512LongMsg.cpp', + 'tests/src/sha2/SHA512ShortMsg.cpp', + 'tests/src/sha2/SHA512Monte.cpp', + 'tests/src/sha2/SHA256LongMsg.cpp', + 'tests/src/sha2/SHA256ShortMsg.cpp', + 'tests/src/sha2/SHA256Monte.cpp', ] ed25519_test_sources = [ - 'tests/src/ed25519/verify_happy.cpp', - 'tests/src/ed25519/verify_sad.cpp', - 'tests/src/ed25519/sign.cpp', - 'tests/src/ed25519/keygen.cpp', + 'tests/src/ed25519/verify_happy.cpp', + 'tests/src/ed25519/verify_sad.cpp', + 'tests/src/ed25519/sign.cpp', + 'tests/src/ed25519/keygen.cpp', ] cc20_p1305_test_sources = [ - 'tests/src/chacha20-poly1305/all.cpp', + 'tests/src/chacha20-poly1305/all.cpp', ] x25519_test_sources = [ - 'tests/src/x25519/all.cpp', + 'tests/src/x25519/all.cpp', ] if not meson.is_subproject() and not meson.is_cross_build() - add_languages('cpp') - subdir('tests') - test( - 'sha2_tests', - executable( - 'sha2_tests', - sha2_test_sources, - include_directories: incdir, - link_with: target, - dependencies: test_dep, - install: false - ) - ) - test( - 'ed25519_tests', - executable( - 'ed25519_tests', - ed25519_test_sources, - include_directories: incdir, - link_with: target, - dependencies: test_dep, - install: false - ) - ) - test( - 'cc20_p1305_tests', - executable( - 'cc20_p1305_tests', - cc20_p1305_test_sources, - include_directories: incdir, - link_with: target, - dependencies: test_dep, - install: false - ) - ) - # Not included by default because it takes ~256 seconds to execute (includes a million-repetition test case) - test( - 'x25519_tests', - executable( - 'x25519_tests', - x25519_test_sources, - include_directories: incdir, - link_with: target, - dependencies: test_dep, - install: false - ) - ) + add_languages('cpp') + subdir('tests') + test( + 'sha2_tests', + executable( + 'sha2_tests', + sha2_test_sources, + include_directories: incdir, + link_with: target, + dependencies: test_dep, + install: false, + ), + ) + test( + 'ed25519_tests', + executable( + 'ed25519_tests', + ed25519_test_sources, + include_directories: incdir, + link_with: target, + dependencies: test_dep, + install: false, + ), + ) + test( + 'cc20_p1305_tests', + executable( + 'cc20_p1305_tests', + cc20_p1305_test_sources, + include_directories: incdir, + link_with: target, + dependencies: test_dep, + install: false, + ), + ) + # Not included by default because it takes ~110 seconds to execute (includes a million-repetition test case) + test( + 'x25519_tests', + executable( + 'x25519_tests', + x25519_test_sources, + include_directories: incdir, + link_with: target, + dependencies: test_dep, + install: false, + ), + ) endif
D persephone-machine.txt

@@ -1,12 +0,0 @@

-[binaries] -c = 'xtensa-esp-elf-gcc' -cpp = 'xtensa-esp-elf-g++' -ar = 'xtensa-esp-elf-ar' -windres = 'xtensa-esp-elf-windres' -strip = 'xtensa-esp-elf-strip' - -[host_machine] -system = 'linux' -cpu_family = 'xtensa' -cpu = 'lx7' -endian = 'little'
D teiresia-machine.txt

@@ -1,12 +0,0 @@

-[binaries] -c = 'aarch64-unknown-linux-musl-gcc' -cpp = 'aarch64-unknown-linux-musl-g++' -ar = 'aarch64-unknown-linux-musl-ar' -windres = 'aarch64-unknown-linux-musl-windres' -strip = 'aarch64-unknown-linux-musl-strip' - -[host_machine] -system = 'linux' -cpu_family = 'aarch64' -cpu = 'aarch64' -endian = 'little'
M tests/src/chacha20-poly1305/all.cpptests/src/chacha20-poly1305/all.cpp

@@ -30,10 +30,6 @@ EXPECT_EQ (memcmp (actual_output, EXPECTED_OUTPUT, sizeof (EXPECTED_OUTPUT)),

0); } -// Encrypt-then-decrypt round trip across a spread of message lengths. This -// exercises the multi-block keystream paths (the 8-block AVX2 and 4-block SIMD -// cores kick in at 512 and 256 bytes respectively) as well as the -// partial-block tail, none of which the single fixed vector above reaches. TEST (ChaCha20_Poly1305, round_trip_lengths) { const uint8_t KEY[32]

@@ -45,9 +41,8 @@ const uint8_t AAD[10]

= { 0x87, 0xe2, 0x29, 0xd4, 0x50, 0x08, 0x45, 0xa0, 0x79, 0xc0 }; // Lengths straddling block (64) and vector-width (256, 512) boundaries. - const size_t lengths[] - = { 0, 1, 63, 64, 65, 127, 128, 255, 256, - 257, 320, 511, 512, 513, 576, 1024, 2048, 4096 }; + const size_t lengths[] = { 0, 1, 63, 64, 65, 127, 128, 255, 256, + 257, 320, 511, 512, 513, 576, 1024, 2048, 4096 }; for (size_t aad_len = 0; aad_len <= sizeof (AAD); aad_len += sizeof (AAD)) {

@@ -71,15 +66,21 @@ }

// frame = ciphertext || 16-byte tag std::vector<uint8_t> frame (len + 16); - memcpy (frame.data (), cipher.data (), len); + if (len != 0) + { + memcpy (frame.data (), cipher.data (), len); + } memcpy (frame.data () + len, mac, 16); bool ok = tct_aead_chacha20_poly1305_decrypt_and_verify ( AAD, aad_len, KEY, NONCE, frame.data (), len, recovered.data ()); EXPECT_TRUE (ok) << "verify failed: aad_len=" << aad_len << " len=" << len; - EXPECT_EQ (memcmp (recovered.data (), plaintext.data (), len), 0) - << "aad_len=" << aad_len << " len=" << len; + if (len != 0) + { + EXPECT_EQ (memcmp (recovered.data (), plaintext.data (), len), 0) + << "aad_len=" << aad_len << " len=" << len; + } // a single flipped ciphertext bit must fail verification if (len > 0)

@@ -93,96 +94,3 @@ }

} } } - -// ---- [email protected] ---- - -static std::vector<uint8_t> -unhex (const char *h) -{ - std::vector<uint8_t> v; - for (size_t i = 0; h[i] && h[i + 1]; i += 2) - { - auto nib = [] (char c) { - return c <= '9' ? c - '0' : (c | 0x20) - 'a' + 10; - }; - v.push_back (static_cast<uint8_t> (nib (h[i]) << 4 | nib (h[i + 1]))); - } - return v; -} - -// build the packet the reference used: 2-byte LE length + 2 zero bytes, then -// payload[i] = i*11 + 1 -static std::vector<uint8_t> -make_packet (uint32_t plen) -{ - std::vector<uint8_t> p (4 + plen); - p[0] = plen & 0xff; - p[1] = (plen >> 8) & 0xff; - for (uint32_t i = 0; i < plen; ++i) - p[4 + i] = static_cast<uint8_t> (i * 11 + 1); - return p; -} - -// Golden vectors from an independent reference implementation that is itself -// anchored against the canonical RFC 8439 ChaCha20 and Poly1305 test vectors. -TEST (ChaCha20_Poly1305, openssh_golden) -{ - auto key = unhex ("030a11181f262d343b424950575e656c737a81888f969da4abb2b9c0" - "c7ced5dce3eaf1f8ff060d141b222930373e454c535a61686f767d84" - "8b9299a0a7aeb5bc"); - auto seq = unhex ("0000000000000005"); - struct - { - uint32_t plen; - const char *out; - } golden[] = { - { 8, "fe5bcdbc9fdefa8cf3de24c316be2bd5af1fdef8f4730379b7fc0df0" }, - { 60, - "ca5bcdbc9fdefa8cf3de24c3f9cfb43fdb24a92f38ad88ebf7209eef95b0a44c" - "f0d8c30674fdaf749bfcd12bb622551bfa0a25bdf1be24d96ef9df544547c240" - "e25732916c0370aea37d9fdb8d374605" }, - }; - for (auto &g : golden) - { - auto packet = make_packet (g.plen); - auto expected = unhex (g.out); - std::vector<uint8_t> out (4 + g.plen + 16); - tct_chacha20_poly1305_openssh_seal (seq.data (), key.data (), - packet.data (), g.plen, out.data ()); - EXPECT_EQ (out, expected) << "seal mismatch, plen=" << g.plen; - } -} - -TEST (ChaCha20_Poly1305, openssh_round_trip) -{ - auto key = unhex ("030a11181f262d343b424950575e656c737a81888f969da4abb2b9c0" - "c7ced5dce3eaf1f8ff060d141b222930373e454c535a61686f767d84" - "8b9299a0a7aeb5bc"); - const uint8_t seq[8] = { 0, 0, 0, 0, 0, 0, 0, 5 }; - - for (uint32_t plen : { 0u, 1u, 8u, 63u, 64u, 65u, 255u, 256u, 512u, 1000u, 4096u }) - { - auto packet = make_packet (plen); - std::vector<uint8_t> frame (4 + plen + 16), recovered (4 + plen); - tct_chacha20_poly1305_openssh_seal (seq, key.data (), packet.data (), - plen, frame.data ()); - - // length field decrypts to the real length - uint8_t declen[4]; - tct_chacha20_poly1305_openssh_decrypt_length (seq, key.data (), - frame.data (), declen); - EXPECT_EQ (memcmp (declen, packet.data (), 4), 0) << "plen=" << plen; - - // open verifies and recovers the packet - EXPECT_TRUE (tct_chacha20_poly1305_openssh_open ( - seq, key.data (), frame.data (), plen, recovered.data ())) - << "plen=" << plen; - EXPECT_EQ (recovered, packet) << "plen=" << plen; - - // any tampered ciphertext byte fails authentication - frame[0] ^= 0x40; - EXPECT_FALSE (tct_chacha20_poly1305_openssh_open ( - seq, key.data (), frame.data (), plen, recovered.data ())) - << "tamper undetected, plen=" << plen; - } -}
M tinycrypt/chacha20_poly1305.htinycrypt/chacha20_poly1305.h

@@ -17,43 +17,11 @@ const uint8_t *aad, const uint64_t aad_len, const uint8_t *key,

const uint8_t *nonce, const uint8_t *frame, const uint64_t ciphertext_len, uint8_t *plaintext_out); -/// Seals an SSH packet with the [email protected] cipher (RFC- -/// incompatible; matches OpenSSH's PROTOCOL.chacha20poly1305). -/// -/// \param seqnr 8-byte packet sequence number (the ChaCha20 nonce). -/// \param key 64-byte key: K_2 = key[0..32) encrypts the payload and -/// derives the Poly1305 key, K_1 = key[32..64) encrypts the -/// 4-byte length field. -/// \param packet 4-byte packet length followed by \p payload_len bytes. -/// \param payload_len number of payload bytes after the length field. -/// \param out receives 4 + \p payload_len ciphertext bytes followed by -/// a 16-byte Poly1305 tag. -void tct_chacha20_poly1305_openssh_seal (const uint8_t *seqnr, - const uint8_t *key, - const uint8_t *packet, - uint32_t payload_len, uint8_t *out); - -/// Decrypts only the 4-byte encrypted length field (with K_1), so a reader can -/// size the packet before authenticating it. -void tct_chacha20_poly1305_openssh_decrypt_length (const uint8_t *seqnr, - const uint8_t *key, - const uint8_t *enc_len, - uint8_t *len_out); - -/// Verifies the tag and opens a [email protected] packet. -/// -/// \param frame 4-byte encrypted length, \p payload_len encrypted payload -/// bytes, then the 16-byte tag. -/// \param payload_len payload length (obtain via -/// tct_chacha20_poly1305_openssh_decrypt_length). -/// \param packet_out on success receives 4 + \p payload_len plaintext bytes -/// (length field followed by payload). -/// \return true and writes \p packet_out on success; false (writing nothing) if -/// authentication fails. -bool tct_chacha20_poly1305_openssh_open (const uint8_t *seqnr, - const uint8_t *key, - const uint8_t *frame, - uint32_t payload_len, - uint8_t *packet_out); +/// Encrypts or decrypts a ChaCha20-encrypted stream (it's symmetric, so +/// they're the same essential operation) +void tct_chacha20_encrypt_or_decrypt (const uint8_t *key, + const uint64_t counter, + const uint8_t *nonce, const uint8_t *in, + const uint32_t in_len, uint8_t *out); -#endif+#endif
D tinycrypt/esp32s3/mult256-gen.py

@@ -1,23 +0,0 @@

-print("xt_fastmult256:") -# `a0` is return address, `a1` is stack pointer, `a2` is input `a`, `a3` is input `b`, `a4` is output buffer -print(f" movi a5, {4 * (16 * 9 + 1)}") -print(" sub a1, a1, a5") -print(" s32i a0, a1, 0") - -# Time to generate the lookup table! -def add36(a, b, out): - print(f" l32i a6, {a}") - print(f" l32i a7, {b}") - print(" add a8, a6, a7") - print(" sub a9, a8, a6") - print(" movi a10, 1") - print(" xor a10, a10, a10") - print(" movltz a11, a10, a9") - -print(" xor a5, a5, a5") -print(" s32i a5, a1, 1") -for i in range(8): - print(f" l32i a5, a2, {i}") - print(f" s32i a5, a1, {2 + i}") -for i in range(1, 16): - pass
A tinycrypt/min32/chacha20_poly1305.c

@@ -0,0 +1,371 @@

+#include <stdbool.h> +#include <stdint.h> + +#include "tinycrypt/chacha20_poly1305.h" + +static void +to_le64 (uint64_t u, uint8_t *x) +{ + for (unsigned int i = 0; i < 8; ++i) + { + x[i] = u & 0xff; + u >>= 8; + } +} + +static uint64_t +from_le64 (const uint8_t *x) +{ + uint64_t u = 0; + for (unsigned int i = 0; i < 8; ++i) + { + u <<= 8; + u |= x[7 - i]; + } + return u; +} + +static void +to_le32 (uint32_t u, uint8_t *x) +{ + for (unsigned int i = 0; i < 4; ++i) + { + x[i] = u & 0xff; + u >>= 8; + } +} + +static uint32_t +from_le32 (const uint8_t *x) +{ + uint32_t u = 0; + for (unsigned int i = 0; i < 4; ++i) + { + u <<= 8; + u |= x[3 - i]; + } + return u; +} + +static void +poly1305_clamp (uint8_t *r) +{ + r[3] &= 15; + r[7] &= 15; + r[11] &= 15; + r[15] &= 15; + r[4] &= 252; + r[8] &= 252; + r[12] &= 252; +} + +static void +add256 (uint32_t *h, const uint32_t *c) +{ + uint64_t accumulator = 0; + for (unsigned int i = 0; i < 8; ++i) + { + accumulator += (uint64_t)h[i] + (uint64_t)c[i]; + h[i] = accumulator & 0xffffffff; + accumulator >>= 32; + } +} + +static void +sub160 (uint32_t *h, const uint32_t *c) +{ + uint64_t accumulator = 0; + for (unsigned int i = 0; i < 5; ++i) + { + accumulator += (uint64_t)(0xffffffff - h[i]) + (uint64_t)c[i]; + h[i] = 0xffffffff - (accumulator & 0xffffffff); + accumulator >>= 32; + } +} + +static void +mult160 (const uint32_t *a, const uint32_t *b, uint32_t *out) +{ + uint32_t a_int[5], b_int[5]; + uint64_t intermediate[10] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + for (unsigned int i = 0; i < 5; ++i) + { + a_int[i] = a[i]; + b_int[i] = b[i]; + out[i] = 0x0; + out[5 + i] = 0x0; + } + for (unsigned int i = 0; i < 5; ++i) + { + for (unsigned int j = 0; j < 5; ++j) + { + intermediate[i + j] += (uint64_t)a_int[i] * (uint64_t)b_int[j]; + intermediate[i + j + 1] += intermediate[i + j] >> 32; + intermediate[i + j] &= 0xffffffff; + } + } + for (unsigned int k = 0; k < 9; ++k) + { + intermediate[k + 1] += intermediate[k] >> 32; + out[k] = intermediate[k] & 0xffffffff; + } + out[9] = intermediate[9] & 0xffffffff; +} + +static void +shr320_by_130 (const uint32_t *in, uint32_t *out) +{ + out[0] = (in[4] >> 2) | (in[5] << 30); + out[1] = (in[5] >> 2) | (in[6] << 30); + out[2] = (in[6] >> 2) | (in[7] << 30); + out[3] = (in[7] >> 2) | (in[8] << 30); + out[4] = (in[8] >> 2) | (in[9] << 30); + out[5] = in[9] >> 2; +} + +/* Fold the bits above 130 into the low 130 via 2^130 = 5 (mod 2^130-5). */ +static void +fold5 (uint32_t *acc) +{ + uint32_t hi[6]; + uint32_t lo[10]; + shr320_by_130 (acc, hi); + lo[0] = acc[0]; + lo[1] = acc[1]; + lo[2] = acc[2]; + lo[3] = acc[3]; + lo[4] = acc[4] & 0x3; + lo[5] = 0x0; + lo[6] = 0x0; + lo[7] = 0x0; + lo[8] = 0x0; + lo[9] = 0x0; + uint64_t c = 0; + uint32_t m[10]; + for (unsigned int i = 0; i < 6; ++i) + { + uint64_t t = (uint64_t)hi[i] * 5 + c; + m[i] = (uint32_t)t; + c = t >> 32; + } + m[6] = (uint32_t)c; + m[7] = m[8] = m[9] = 0x0; + c = 0; + for (unsigned int i = 0; i < 10; ++i) + { + uint64_t t = (uint64_t)m[i] + (uint64_t)lo[i] + c; + acc[i] = (uint32_t)t; + c = t >> 32; + } +} + +static void +modp320 (uint32_t *in, uint32_t *out) +{ + uint32_t acc[10] = { in[0], in[1], in[2], in[3], in[4], + in[5], in[6], in[7], in[8], in[9] }; + fold5 (acc); + fold5 (acc); + const uint32_t P[5] + = { 0xfffffffb, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000003 }; + uint32_t buf[5]; + for (unsigned int i = 0; i < 5; ++i) + { + buf[i] = acc[i]; + } + sub160 (buf, P); + uint32_t *res = (buf[4] >> 31) ? acc : buf; + for (unsigned int i = 0; i < 5; ++i) + { + out[i] = res[i]; + } +} + +static void +poly1305_mac_rolling (const uint8_t *msg, const uint8_t *key, + const uint8_t blocklen, uint32_t *a) +{ + uint8_t r[32]; + for (unsigned int i = 16; i < 32; ++i) + { + r[i] = 0; + } + for (unsigned int i = 0; i < 16; ++i) + { + r[i] = key[i]; + } + + poly1305_clamp (r); + uint8_t n[32]; + for (unsigned int i = blocklen; i < 32; ++i) + { + n[i] = 0x0; + } + for (unsigned int i = 0; i < 16 && i < blocklen; ++i) + { + n[i] = msg[i]; + } + n[blocklen] = 0x1; + uint32_t n_chunked[8]; + uint32_t r_chunked[8]; + for (unsigned int i = 0; i < 8; ++i) + { + n_chunked[i] = from_le32 (n + 4 * i); + r_chunked[i] = from_le32 (r + 4 * i); + } + add256 (a, n_chunked); + uint32_t intermediate[10]; + mult160 (r_chunked, a, intermediate); + modp320 (intermediate, a); + for (unsigned int i = 5; i < 8; ++i) + { + a[i] = 0x0; + } +} + +static void +poly1305_mac_init (uint32_t *a) +{ + for (unsigned int i = 0; i < 8; ++i) + { + a[i] = 0x0; + } +} + +static void +poly1305_mac_finish (uint32_t *a, const uint8_t *key) +{ + uint32_t s[8]; + for (unsigned int i = 4; i < 8; ++i) + { + s[i] = 0; + } + for (unsigned int i = 0; i < 4; ++i) + { + s[i] = from_le32 (key + 16 + 4 * i); + } + add256 (a, s); +} + +bool +tct_aead_chacha20_poly1305_decrypt_and_verify ( + const uint8_t *aad, const uint64_t aad_len, const uint8_t *key, + const uint8_t *nonce, const uint8_t *frame, const uint64_t ciphertext_len, + uint8_t *plaintext_out) +{ + uint8_t otk[64]; + const uint8_t ZERO[64] + = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + tct_chacha20_encrypt_or_decrypt (key, 0, nonce, ZERO, sizeof (ZERO), otk); + uint32_t mac_chunked[8]; + poly1305_mac_init (mac_chunked); + uint8_t buf[16]; + uint64_t total_len = 16 + aad_len + ciphertext_len; + uint8_t aad_len_le[8], ciphertext_len_le[8]; + to_le64 (aad_len, aad_len_le); + to_le64 (ciphertext_len, ciphertext_len_le); + for (unsigned int i = 0; i < total_len; ++i) + { + if (i < aad_len) + { + buf[i % 16] = aad[i]; + } + else if (i < aad_len + 8) + { + buf[i % 16] = aad_len_le[i - aad_len]; + } + else if (i < aad_len + 8 + ciphertext_len) + { + buf[i % 16] = frame[i - aad_len - 8]; + } + else if (i < aad_len + 16 + ciphertext_len) + { + buf[i % 16] = ciphertext_len_le[i - aad_len - 8 - ciphertext_len]; + } + if (i % 16 == 15) + { + poly1305_mac_rolling (buf, otk, 16, mac_chunked); + } + } + if (total_len % 16 != 0) + { + poly1305_mac_rolling (buf, otk, total_len % 16, mac_chunked); + } + poly1305_mac_finish (mac_chunked, otk); + uint32_t acc = 0x0; + for (unsigned int i = 0; i < 4; ++i) + { + acc |= from_le32 (frame + ciphertext_len + i * 4) ^ mac_chunked[i]; + } + if (acc != 0x0) + { + return false; + } + tct_chacha20_encrypt_or_decrypt (key, 1, nonce, frame, ciphertext_len, + plaintext_out); + return true; +} + +void +tct_aead_chacha20_poly1305_encrypt (const uint8_t *aad, const uint64_t aad_len, + const uint8_t *key, const uint8_t *nonce, + const uint8_t *plaintext, + const uint64_t plaintext_len, + uint8_t *cipher_out, uint8_t *mac_out) +{ + uint8_t otk[64]; + const uint8_t ZERO[64] + = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + tct_chacha20_encrypt_or_decrypt (key, 0, nonce, ZERO, sizeof (ZERO), otk); + tct_chacha20_encrypt_or_decrypt (key, 1, nonce, plaintext, plaintext_len, + cipher_out); + uint32_t mac_chunked[8]; + poly1305_mac_init (mac_chunked); + uint8_t buf[16]; + uint64_t total_len = 16 + aad_len + plaintext_len; + uint8_t aad_len_le[8], plaintext_len_le[8]; + to_le64 (aad_len, aad_len_le); + to_le64 (plaintext_len, plaintext_len_le); + for (unsigned int i = 0; i < total_len; ++i) + { + if (i < aad_len) + { + buf[i % 16] = aad[i]; + } + else if (i < aad_len + 8) + { + buf[i % 16] = aad_len_le[i - aad_len]; + } + else if (i < aad_len + 8 + plaintext_len) + { + buf[i % 16] = cipher_out[i - aad_len - 8]; + } + else if (i < aad_len + 16 + plaintext_len) + { + buf[i % 16] = plaintext_len_le[i - aad_len - 8 - plaintext_len]; + } + if (i % 16 == 15) + { + poly1305_mac_rolling (buf, otk, 16, mac_chunked); + } + } + if (total_len % 16 != 0) + { + poly1305_mac_rolling (buf, otk, total_len % 16, mac_chunked); + } + poly1305_mac_finish (mac_chunked, otk); + for (unsigned int i = 0; i < 4; ++i) + { + to_le32 (mac_chunked[i], mac_out + 4 * i); + } +}
A tinycrypt/min64/chacha20_poly1305.c

@@ -0,0 +1,322 @@

+#include <stdbool.h> +#include <stdint.h> + +#include "tinycrypt/chacha20_poly1305.h" + +static void +to_le64 (uint64_t u, uint8_t *x) +{ + for (unsigned int i = 0; i < 8; ++i) + { + x[i] = u & 0xff; + u >>= 8; + } +} + +static uint64_t +from_le64 (const uint8_t *x) +{ + uint64_t u = 0; + for (unsigned int i = 0; i < 8; ++i) + { + u <<= 8; + u |= x[7 - i]; + } + return u; +} + +static void +poly1305_clamp (uint8_t *r) +{ + r[3] &= 15; + r[7] &= 15; + r[11] &= 15; + r[15] &= 15; + r[4] &= 252; + r[8] &= 252; + r[12] &= 252; +} + +static void +add256 (uint64_t *h, const uint64_t *c) +{ + __uint128_t accumulator = 0; + for (unsigned int i = 0; i < 4; ++i) + { + accumulator += (__uint128_t)h[i] + (__uint128_t)c[i]; + h[i] = accumulator & 0xffffffffffffffff; + accumulator >>= 64; + } +} + +static void +mult192 (const uint64_t *a, const uint64_t *b, uint64_t *out) +{ + uint64_t a_int[3], b_int[3]; + __uint128_t intermediate[6] = { + 0, 0, 0, 0, 0, 0, + }; + for (unsigned int i = 0; i < 3; ++i) + { + a_int[i] = a[i]; + b_int[i] = b[i]; + out[i] = 0x0; + out[3 + i] = 0x0; + } + for (unsigned int i = 0; i < 3; ++i) + { + for (unsigned int j = 0; j < 3; ++j) + { + intermediate[i + j] += (__uint128_t)a_int[i] * (__uint128_t)b_int[j]; + intermediate[i + j + 1] += intermediate[i + j] >> 64; + intermediate[i + j] &= 0xffffffffffffffff; + } + } + for (unsigned int k = 0; k < 5; ++k) + { + intermediate[k + 1] += intermediate[k] >> 64; + out[k] = intermediate[k] & 0xffffffffffffffff; + } + out[5] = intermediate[5] & 0xffffffffffffffff; +} + +static void +shr320_by_130 (const uint64_t *in, uint64_t *out) +{ + out[0] = (in[2] >> 2) | (in[3] << 62); + out[1] = (in[3] >> 2) | (in[4] << 62); + out[2] = in[4] >> 2; +} + +/* Fold the bits above 130 into the low 130 via 2^130 = 5 (mod 2^130-5). */ +static void +fold5 (uint64_t *acc) +{ + uint64_t hi[3]; + shr320_by_130 (acc, hi); + uint64_t lo0 = acc[0], lo1 = acc[1], lo2 = acc[2] & 0x3; + __uint128_t c = 0; + uint64_t m[4]; + for (unsigned int i = 0; i < 3; ++i) + { + __uint128_t t = (__uint128_t)hi[i] * 5 + c; + m[i] = (uint64_t)t; + c = t >> 64; + } + m[3] = (uint64_t)c; + __uint128_t s = (__uint128_t)m[0] + lo0; + acc[0] = (uint64_t)s; + c = s >> 64; + s = (__uint128_t)m[1] + lo1 + c; + acc[1] = (uint64_t)s; + c = s >> 64; + s = (__uint128_t)m[2] + lo2 + c; + acc[2] = (uint64_t)s; + c = s >> 64; + s = (__uint128_t)m[3] + c; + acc[3] = (uint64_t)s; + acc[4] = (uint64_t)(s >> 64); +} + +static void +modp320 (uint64_t *in, uint64_t *out) +{ + uint64_t acc[5] = { in[0], in[1], in[2], in[3], in[4] }; + fold5 (acc); + fold5 (acc); /* value now < 2^130 + 80 */ + /* constant-time freeze: if value + 5 carries past bit 130, subtract p */ + __uint128_t c = 5; + __uint128_t s = (__uint128_t)acc[0] + c; + uint64_t t0 = (uint64_t)s; + c = s >> 64; + s = (__uint128_t)acc[1] + c; + uint64_t t1 = (uint64_t)s; + c = s >> 64; + s = (__uint128_t)acc[2] + c; + uint64_t t2 = (uint64_t)s; + uint64_t mask = (uint64_t)0 - ((t2 >> 2) & 1); + out[0] = (t0 & mask) | (acc[0] & ~mask); + out[1] = (t1 & mask) | (acc[1] & ~mask); + out[2] = ((t2 & 0x3) & mask) | (acc[2] & ~mask); + out[3] = 0; +} + +static void +poly1305_mac_rolling (const uint8_t *msg, const uint8_t *key, + const uint8_t blocklen, uint64_t *a) +{ + uint8_t r[32]; + for (unsigned int i = 0; i < 32; ++i) + { + r[i] = 0; + } + for (unsigned int i = 0; i < 16; ++i) + { + r[i] = key[i]; + } + + poly1305_clamp (r); + uint8_t n[32]; + for (unsigned int i = blocklen; i < 32; ++i) + { + n[i] = 0x0; + } + for (unsigned int i = 0; i < 16 && i < blocklen; ++i) + { + n[i] = msg[i]; + } + n[blocklen] = 0x1; + uint64_t n_chunked[4]; + uint64_t r_chunked[4]; + for (unsigned int i = 0; i < 4; ++i) + { + n_chunked[i] = from_le64 (n + 8 * i); + r_chunked[i] = from_le64 (r + 8 * i); + } + add256 (a, n_chunked); + uint64_t intermediate[6]; + mult192 (r_chunked, a, intermediate); + modp320 (intermediate, a); +} + +static void +poly1305_mac_init (uint64_t *a) +{ + for (unsigned int i = 0; i < 4; ++i) + { + a[i] = 0x0; + } +} + +static void +poly1305_mac_finish (uint64_t *a, const uint8_t *key) +{ + uint64_t s[4]; + for (unsigned int i = 2; i < 4; ++i) + { + s[i] = 0; + } + for (unsigned int i = 0; i < 2; ++i) + { + s[i] = from_le64 (key + 16 + 8 * i); + } + add256 (a, s); +} + +bool +tct_aead_chacha20_poly1305_decrypt_and_verify ( + const uint8_t *aad, const uint64_t aad_len, const uint8_t *key, + const uint8_t *nonce, const uint8_t *frame, const uint64_t ciphertext_len, + uint8_t *plaintext_out) +{ + uint8_t otk[64]; + const uint8_t ZERO[64] + = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + tct_chacha20_encrypt_or_decrypt (key, 0, nonce, ZERO, sizeof (ZERO), otk); + uint64_t mac_chunked[4]; + poly1305_mac_init (mac_chunked); + uint8_t buf[16]; + uint64_t total_len = 16 + aad_len + ciphertext_len; + uint8_t aad_len_le[8], ciphertext_len_le[8]; + to_le64 (aad_len, aad_len_le); + to_le64 (ciphertext_len, ciphertext_len_le); + for (unsigned int i = 0; i < total_len; ++i) + { + if (i < aad_len) + { + buf[i % 16] = aad[i]; + } + else if (i < aad_len + 8) + { + buf[i % 16] = aad_len_le[i - aad_len]; + } + else if (i < aad_len + 8 + ciphertext_len) + { + buf[i % 16] = frame[i - aad_len - 8]; + } + else if (i < aad_len + 16 + ciphertext_len) + { + buf[i % 16] = ciphertext_len_le[i - aad_len - 8 - ciphertext_len]; + } + if (i % 16 == 15) + { + poly1305_mac_rolling (buf, otk, 16, mac_chunked); + } + } + if (total_len % 16 != 0) + { + poly1305_mac_rolling (buf, otk, total_len % 16, mac_chunked); + } + poly1305_mac_finish (mac_chunked, otk); + if (((from_le64 (frame + ciphertext_len) ^ mac_chunked[0]) + | (from_le64 (frame + ciphertext_len + 8) ^ mac_chunked[1])) + != 0) + { + return false; + } + tct_chacha20_encrypt_or_decrypt (key, 1, nonce, frame, ciphertext_len, + plaintext_out); + return true; +} + +void +tct_aead_chacha20_poly1305_encrypt (const uint8_t *aad, const uint64_t aad_len, + const uint8_t *key, const uint8_t *nonce, + const uint8_t *plaintext, + const uint64_t plaintext_len, + uint8_t *cipher_out, uint8_t *mac_out) +{ + uint8_t otk[64]; + const uint8_t ZERO[64] + = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + tct_chacha20_encrypt_or_decrypt (key, 0, nonce, ZERO, sizeof (ZERO), otk); + tct_chacha20_encrypt_or_decrypt (key, 1, nonce, plaintext, plaintext_len, + cipher_out); + uint64_t mac_chunked[4]; + poly1305_mac_init (mac_chunked); + uint8_t buf[16]; + uint64_t total_len = 16 + aad_len + plaintext_len; + uint8_t aad_len_le[8], plaintext_len_le[8]; + to_le64 (aad_len, aad_len_le); + to_le64 (plaintext_len, plaintext_len_le); + for (unsigned int i = 0; i < total_len; ++i) + { + if (i < aad_len) + { + buf[i % 16] = aad[i]; + } + else if (i < aad_len + 8) + { + buf[i % 16] = aad_len_le[i - aad_len]; + } + else if (i < aad_len + 8 + plaintext_len) + { + buf[i % 16] = cipher_out[i - aad_len - 8]; + } + else if (i < aad_len + 16 + plaintext_len) + { + buf[i % 16] = plaintext_len_le[i - aad_len - 8 - plaintext_len]; + } + if (i % 16 == 15) + { + poly1305_mac_rolling (buf, otk, 16, mac_chunked); + } + } + if (total_len % 16 != 0) + { + poly1305_mac_rolling (buf, otk, total_len % 16, mac_chunked); + } + poly1305_mac_finish (mac_chunked, otk); + for (unsigned int i = 0; i < 2; ++i) + { + to_le64 (mac_chunked[i], mac_out + 8 * i); + } +}
A tinycrypt/portable/chacha20.c

@@ -0,0 +1,417 @@

+#include <stdbool.h> +#include <stdint.h> + +#include "tinycrypt/chacha20_poly1305.h" + +typedef uint32_t dwpacked __attribute__ ((vector_size (16))); +typedef uint8_t bytes16 __attribute__ ((vector_size (16))); + +#if TCT_SIMD128 +static dwpacked +rotl16 (dwpacked x) +{ + bytes16 b = (bytes16)x; + b = __builtin_shufflevector (b, b, 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, + 15, 12, 13); + return (dwpacked)b; +} +static dwpacked +rotl8 (dwpacked x) +{ + bytes16 b = (bytes16)x; + b = __builtin_shufflevector (b, b, 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, + 12, 13, 14); + return (dwpacked)b; +} +#else +static dwpacked +rotl16 (dwpacked x) +{ + return (x << 16) | (x >> 16); +} +static dwpacked +rotl8 (dwpacked x) +{ + return (x << 8) | (x >> 24); +} +#endif + +static dwpacked +rotl_n (dwpacked x, int c) +{ + return (x << c) | (x >> (32 - c)); +} + +static uint32_t +from_le32 (const uint8_t *x) +{ + uint32_t u = x[3]; + u = (u << 8) | x[2]; + u = (u << 8) | x[1]; + return (u << 8) | x[0]; +} + +static void +to_le32 (uint32_t u, uint8_t *x) +{ + for (unsigned int i = 0; i < 4; ++i) + { + x[i] = u & 0xFF; + u >>= 8; + } +} + +#define CC20_QR(a, b, c, d) \ + do \ + { \ + a += b; \ + d ^= a; \ + d = rotl16 (d); \ + c += d; \ + b ^= c; \ + b = rotl_n (b, 12); \ + a += b; \ + d ^= a; \ + d = rotl8 (d); \ + c += d; \ + b ^= c; \ + b = rotl_n (b, 7); \ + } \ + while (false) + +static dwpacked +splat (uint32_t v) +{ + return (dwpacked){ v, v, v, v }; +} + +/* Counter/nonce row in the DJB / OpenSSH layout: a 64-bit block counter in + words 12/13 (little-endian) and a 64-bit nonce in words 14/15. This matches + standard ChaCha20 as used by [email protected]. */ +static dwpacked +cc20_counter_row (uint64_t counter, uint32_t n0, uint32_t n1) +{ + return (dwpacked){ (uint32_t)counter, (uint32_t)(counter >> 32), n0, n1 }; +} + +/* One ChaCha20 block; keystream returned in four vectors (row layout). */ +static void +chacha_core (dwpacked s0, dwpacked s1, dwpacked s2, dwpacked s3, + dwpacked out[4]) +{ + dwpacked x0 = s0, x1 = s1, x2 = s2, x3 = s3; + for (uint32_t i = 0; i < 10; ++i) + { + CC20_QR (x0, x1, x2, x3); + x1 = __builtin_shufflevector (x1, x1, 1, 2, 3, 0); + x2 = __builtin_shufflevector (x2, x2, 2, 3, 0, 1); + x3 = __builtin_shufflevector (x3, x3, 3, 0, 1, 2); + CC20_QR (x0, x1, x2, x3); + x1 = __builtin_shufflevector (x1, x1, 3, 0, 1, 2); + x2 = __builtin_shufflevector (x2, x2, 2, 3, 0, 1); + x3 = __builtin_shufflevector (x3, x3, 1, 2, 3, 0); + } + out[0] = x0 + s0; + out[1] = x1 + s1; + out[2] = x2 + s2; + out[3] = x3 + s3; +} + +#ifdef TCT_LITTLE_ENDIAN +static void +cc20_xor64 (const uint8_t *in, const dwpacked ks[4], uint8_t *out) +{ + for (unsigned int k = 0; k < 4; ++k) + { + dwpacked p; + __builtin_memcpy (&p, in + 16 * k, 16); + p ^= ks[k]; + __builtin_memcpy (out + 16 * k, &p, 16); + } +} +#else +static void +cc20_xor64 (const uint8_t *in, const dwpacked ks[4], uint8_t *out) +{ + for (unsigned int k = 0; k < 4; ++k) + { + dwpacked p; + __builtin_memcpy (&p, in + 16 * k, 16); + bytes16 be = (bytes16)p; + be = __builtin_shufflevector(be, be, 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12); + be ^= ks[k]; + be = __builtin_shufflevector(be, be, 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12); + __builtin_memcpy (out + 16 * k, &be, 16); + } +} +#endif + +/* Transpose a 4x4 word matrix held in four vectors (rows <-> columns). */ +static void +transpose4 (dwpacked *r0, dwpacked *r1, dwpacked *r2, dwpacked *r3) +{ + dwpacked a0 = __builtin_shufflevector (*r0, *r1, 0, 4, 1, 5); + dwpacked a1 = __builtin_shufflevector (*r0, *r1, 2, 6, 3, 7); + dwpacked a2 = __builtin_shufflevector (*r2, *r3, 0, 4, 1, 5); + dwpacked a3 = __builtin_shufflevector (*r2, *r3, 2, 6, 3, 7); + *r0 = __builtin_shufflevector (a0, a2, 0, 1, 4, 5); + *r1 = __builtin_shufflevector (a0, a2, 2, 3, 6, 7); + *r2 = __builtin_shufflevector (a1, a3, 0, 1, 4, 5); + *r3 = __builtin_shufflevector (a1, a3, 2, 3, 6, 7); +} + +/* Encrypt exactly four blocks held in vertical layout (lane = block) in + v[16]. Removes the per-round diagonalization shuffles the row core needs. */ +static void +cc20_xor_x4 (dwpacked v[16], const uint8_t *pt, uint8_t *out) +{ + dwpacked in[16]; + for (unsigned int k = 0; k < 16; ++k) + in[k] = v[k]; + for (unsigned int r = 0; r < 10; ++r) + { + CC20_QR (v[0], v[4], v[8], v[12]); + CC20_QR (v[1], v[5], v[9], v[13]); + CC20_QR (v[2], v[6], v[10], v[14]); + CC20_QR (v[3], v[7], v[11], v[15]); + CC20_QR (v[0], v[5], v[10], v[15]); + CC20_QR (v[1], v[6], v[11], v[12]); + CC20_QR (v[2], v[7], v[8], v[13]); + CC20_QR (v[3], v[4], v[9], v[14]); + } + for (unsigned int k = 0; k < 16; ++k) + v[k] += in[k]; + transpose4 (&v[0], &v[1], &v[2], &v[3]); + transpose4 (&v[4], &v[5], &v[6], &v[7]); + transpose4 (&v[8], &v[9], &v[10], &v[11]); + transpose4 (&v[12], &v[13], &v[14], &v[15]); + for (unsigned int j = 0; j < 4; ++j) + { + const dwpacked ks[4] = { v[j], v[4 + j], v[8 + j], v[12 + j] }; + cc20_xor64 (pt + 64 * j, ks, out + 64 * j); + } +} + +#ifdef TCT_SIMD256 +typedef uint32_t qwpacked __attribute__ ((vector_size (32))); +typedef uint8_t bytes32 __attribute__ ((vector_size (32))); + +static qwpacked +rotl16_x8 (qwpacked x) +{ + bytes32 b = (bytes32)x; + b = __builtin_shufflevector (b, b, 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, + 15, 12, 13, 18, 19, 16, 17, 22, 23, 20, 21, 26, + 27, 24, 25, 30, 31, 28, 29); + return (qwpacked)b; +} +static qwpacked +rotl8_x8 (qwpacked x) +{ + bytes32 b = (bytes32)x; + b = __builtin_shufflevector (b, b, 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, + 12, 13, 14, 19, 16, 17, 18, 23, 20, 21, 22, 27, + 24, 25, 26, 31, 28, 29, 30); + return (qwpacked)b; +} +static qwpacked +rotl_n_x8 (qwpacked x, int c) +{ + return (x << c) | (x >> (32 - c)); +} + +#define CC20_QR8(a, b, c, d) \ + do \ + { \ + a += b; \ + d ^= a; \ + d = rotl16_x8 (d); \ + c += d; \ + b ^= c; \ + b = rotl_n_x8 (b, 12); \ + a += b; \ + d ^= a; \ + d = rotl8_x8 (d); \ + c += d; \ + b ^= c; \ + b = rotl_n_x8 (b, 7); \ + } \ + while (false) + +#define CC20_UNPACKLO32(a, b) \ + __builtin_shufflevector (a, b, 0, 8, 1, 9, 4, 12, 5, 13) +#define CC20_UNPACKHI32(a, b) \ + __builtin_shufflevector (a, b, 2, 10, 3, 11, 6, 14, 7, 15) +#define CC20_UNPACKLO64(a, b) \ + __builtin_shufflevector (a, b, 0, 1, 8, 9, 4, 5, 12, 13) +#define CC20_UNPACKHI64(a, b) \ + __builtin_shufflevector (a, b, 2, 3, 10, 11, 6, 7, 14, 15) +#define CC20_PERM128_LO(a, b) \ + __builtin_shufflevector (a, b, 0, 1, 2, 3, 8, 9, 10, 11) +#define CC20_PERM128_HI(a, b) \ + __builtin_shufflevector (a, b, 4, 5, 6, 7, 12, 13, 14, 15) + +static void +transpose8 (qwpacked r[8]) +{ + qwpacked t0 = CC20_UNPACKLO32 (r[0], r[1]), + t1 = CC20_UNPACKHI32 (r[0], r[1]); + qwpacked t2 = CC20_UNPACKLO32 (r[2], r[3]), + t3 = CC20_UNPACKHI32 (r[2], r[3]); + qwpacked t4 = CC20_UNPACKLO32 (r[4], r[5]), + t5 = CC20_UNPACKHI32 (r[4], r[5]); + qwpacked t6 = CC20_UNPACKLO32 (r[6], r[7]), + t7 = CC20_UNPACKHI32 (r[6], r[7]); + qwpacked u0 = CC20_UNPACKLO64 (t0, t2), u1 = CC20_UNPACKHI64 (t0, t2); + qwpacked u2 = CC20_UNPACKLO64 (t1, t3), u3 = CC20_UNPACKHI64 (t1, t3); + qwpacked u4 = CC20_UNPACKLO64 (t4, t6), u5 = CC20_UNPACKHI64 (t4, t6); + qwpacked u6 = CC20_UNPACKLO64 (t5, t7), u7 = CC20_UNPACKHI64 (t5, t7); + r[0] = CC20_PERM128_LO (u0, u4); + r[4] = CC20_PERM128_HI (u0, u4); + r[1] = CC20_PERM128_LO (u1, u5); + r[5] = CC20_PERM128_HI (u1, u5); + r[2] = CC20_PERM128_LO (u2, u6); + r[6] = CC20_PERM128_HI (u2, u6); + r[3] = CC20_PERM128_LO (u3, u7); + r[7] = CC20_PERM128_HI (u3, u7); +} + +static qwpacked +splat8 (uint32_t v) +{ + return (qwpacked){ v, v, v, v, v, v, v, v }; +} + +/* Encrypt exactly eight blocks held in vertical layout in v[16]. */ +static void +cc20_xor_x8 (qwpacked v[16], const uint8_t *pt, uint8_t *out) +{ + qwpacked in[16]; + for (unsigned int k = 0; k < 16; ++k) + in[k] = v[k]; + for (unsigned int r = 0; r < 10; ++r) + { + CC20_QR8 (v[0], v[4], v[8], v[12]); + CC20_QR8 (v[1], v[5], v[9], v[13]); + CC20_QR8 (v[2], v[6], v[10], v[14]); + CC20_QR8 (v[3], v[7], v[11], v[15]); + CC20_QR8 (v[0], v[5], v[10], v[15]); + CC20_QR8 (v[1], v[6], v[11], v[12]); + CC20_QR8 (v[2], v[7], v[8], v[13]); + CC20_QR8 (v[3], v[4], v[9], v[14]); + } + for (unsigned int k = 0; k < 16; ++k) + v[k] += in[k]; + /* words 0..7 and 8..15 transposed independently -> lane j is block j */ + transpose8 (&v[0]); + transpose8 (&v[8]); + for (unsigned int j = 0; j < 8; ++j) + { + qwpacked p0, p1; + __builtin_memcpy (&p0, pt + 64 * j, 32); + __builtin_memcpy (&p1, pt + 64 * j + 32, 32); + p0 ^= v[j]; + p1 ^= v[8 + j]; + __builtin_memcpy (out + 64 * j, &p0, 32); + __builtin_memcpy (out + 64 * j + 32, &p1, 32); + } +} +#endif /* TCT_SIMD256 */ + +void +tct_chacha20_encrypt_or_decrypt (const uint8_t *key, const uint64_t counter, + const uint8_t *nonce, const uint8_t *in, + const uint32_t in_len, uint8_t *out) +{ + /* Constant/key/nonce state is invariant across blocks; build it once. */ + const dwpacked s0 = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + const dwpacked s1 = { from_le32 (key), from_le32 (key + 4), + from_le32 (key + 8), from_le32 (key + 12) }; + const dwpacked s2 = { from_le32 (key + 16), from_le32 (key + 20), + from_le32 (key + 24), from_le32 (key + 28) }; + const uint32_t n0 = from_le32 (nonce), n1 = from_le32 (nonce + 4); + const uint32_t full = in_len / 64; + uint32_t i = 0; + +#ifdef TCT_SIMD256 + { + const qwpacked b[12] + = { splat8 (s0[0]), splat8 (s0[1]), splat8 (s0[2]), splat8 (s0[3]), + splat8 (s1[0]), splat8 (s1[1]), splat8 (s1[2]), splat8 (s1[3]), + splat8 (s2[0]), splat8 (s2[1]), splat8 (s2[2]), splat8 (s2[3]) }; + const qwpacked bn0 = splat8 (n0), bn1 = splat8 (n1); + for (; i + 8 <= full; i += 8) + { + uint64_t c[8]; + for (unsigned int j = 0; j < 8; ++j) + c[j] = counter + i + j; + qwpacked lo = { (uint32_t)c[0], (uint32_t)c[1], (uint32_t)c[2], + (uint32_t)c[3], (uint32_t)c[4], (uint32_t)c[5], + (uint32_t)c[6], (uint32_t)c[7] }; + qwpacked hi = { (uint32_t)(c[0] >> 32), (uint32_t)(c[1] >> 32), + (uint32_t)(c[2] >> 32), (uint32_t)(c[3] >> 32), + (uint32_t)(c[4] >> 32), (uint32_t)(c[5] >> 32), + (uint32_t)(c[6] >> 32), (uint32_t)(c[7] >> 32) }; + qwpacked v[16] = { b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], + b[8], b[9], b[10], b[11], lo, hi, bn0, bn1 }; + cc20_xor_x8 (v, in + 64 * i, out + 64 * i); + } + } +#endif + + dwpacked bc[12]; + for (unsigned int j = 0; j < 4; ++j) + { + bc[j] = splat (s0[j]); + bc[4 + j] = splat (s1[j]); + bc[8 + j] = splat (s2[j]); + } + const dwpacked bn0 = splat (n0), bn1 = splat (n1); + for (; i + 4 <= full; i += 4) + { + uint64_t c0 = counter + i, c1 = counter + i + 1, c2 = counter + i + 2, + c3 = counter + i + 3; + dwpacked v[16] + = { bc[0], + bc[1], + bc[2], + bc[3], + bc[4], + bc[5], + bc[6], + bc[7], + bc[8], + bc[9], + bc[10], + bc[11], + (dwpacked){ (uint32_t)c0, (uint32_t)c1, (uint32_t)c2, + (uint32_t)c3 }, + (dwpacked){ (uint32_t)(c0 >> 32), (uint32_t)(c1 >> 32), + (uint32_t)(c2 >> 32), (uint32_t)(c3 >> 32) }, + bn0, + bn1 }; + cc20_xor_x4 (v, in + 64 * i, out + 64 * i); + } + + /* Remaining whole blocks (fewer than the vector width), one at a time. */ + for (; i < full; ++i) + { + dwpacked s3 = cc20_counter_row (counter + i, n0, n1); + dwpacked ks[4]; + chacha_core (s0, s1, s2, s3, ks); + cc20_xor64 (in + 64 * i, ks, out + 64 * i); + } + + /* Trailing partial block. */ + if ((in_len % 64) != 0) + { + dwpacked s3 = cc20_counter_row (counter + full, n0, n1); + dwpacked ks[4]; + chacha_core (s0, s1, s2, s3, ks); + uint8_t key_stream[64]; + for (unsigned int k = 0; k < 16; ++k) + to_le32 (ks[k / 4][k % 4], key_stream + 4 * k); + for (uint32_t j = 0; j < in_len % 64; ++j) + out[64 * full + j] = in[64 * full + j] ^ key_stream[j]; + } +}
D tinycrypt/portable/chacha20_poly1305.c

@@ -1,392 +0,0 @@

-#include <stdbool.h> -#include <stdint.h> - -typedef uint32_t dwpacked __attribute__ ((vector_size (16))); - -static dwpacked -rotl_32 (dwpacked x, int c) -{ - return (x << c) | (x >> (32 - c)); -} - -static uint32_t -from_le32 (const uint8_t *x) -{ - uint32_t u = x[3]; - u = (u << 8) | x[2]; - u = (u << 8) | x[1]; - return (u << 8) | x[0]; -} - -static void -to_le32 (uint32_t u, uint8_t *x) -{ - for (unsigned int i = 0; i < 4; ++i) - { - x[i] = u & 0xFF; - u >>= 8; - } -} - -#define CC20_QR(state, a, b, c, d) \ - do \ - { \ - state[a] += state[b]; \ - state[d] ^= state[a]; \ - state[d] = rotl_32 (state[d], 16); \ - state[c] += state[d]; \ - state[b] ^= state[c]; \ - state[b] = rotl_32 (state[b], 12); \ - state[a] += state[b]; \ - state[d] ^= state[a]; \ - state[d] = rotl_32 (state[d], 8); \ - state[c] += state[d]; \ - state[b] ^= state[c]; \ - state[b] = rotl_32 (state[b], 7); \ - } \ - while (false); - -static void -cc20_block (const uint8_t *key, const uint16_t counter, const uint8_t *nonce, - uint8_t *state_out) -{ - dwpacked initial_state[4] - = { { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 } }; - initial_state[1] = (dwpacked){ from_le32 (key), from_le32 (key + 4), - from_le32 (key + 8), from_le32 (key + 12) }; - initial_state[2] = (dwpacked){ from_le32 (key + 16), from_le32 (key + 20), - from_le32 (key + 24), from_le32 (key + 28) }; - initial_state[3] = (dwpacked){ counter & 0xff, (counter >> 8) & 0xff, - from_le32 (nonce), from_le32 (nonce + 4) }; - dwpacked state[4]; - for (uint32_t i = 0; i < 4; ++i) - { - state[i] = initial_state[i]; - } - for (uint32_t i = 0; i < 10; ++i) - { - CC20_QR (state, 0, 1, 2, 3); - state[1] = __builtin_shufflevector (state[1], state[1], 1, 2, 3, 0); - state[2] = __builtin_shufflevector (state[2], state[2], 2, 3, 0, 1); - state[3] = __builtin_shufflevector (state[3], state[3], 3, 0, 1, 2); - CC20_QR (state, 0, 1, 2, 3); - state[1] = __builtin_shufflevector (state[1], state[1], 3, 0, 1, 2); - state[2] = __builtin_shufflevector (state[2], state[2], 2, 3, 0, 1); - state[3] = __builtin_shufflevector (state[3], state[3], 1, 2, 3, 0); - } - - for (uint32_t i = 0; i < 4; ++i) - { - state[i] += initial_state[i]; - } - for (unsigned int i = 0; i < 16; ++i) - { - to_le32 (state[i / 4][i % 4], state_out + 4 * i); - } -} - -static void -cc20_encrypt (const uint8_t *key, const uint32_t counter, const uint8_t *nonce, - const uint8_t *plaintext, const uint32_t plaintext_len, - uint8_t *encrypted_out) -{ - uint8_t key_stream[64]; - for (uint32_t i = 0; i < plaintext_len / 64; ++i) - { - cc20_block (key, counter + i, nonce, key_stream); - for (uint32_t j = 0; j < 64; ++j) - { - encrypted_out[i * 64 + j] = plaintext[i * 64 + j] ^ key_stream[j]; - } - } - if ((plaintext_len % 64) != 0) - { - uint32_t i = plaintext_len / 64; - cc20_block (key, counter + i, nonce, key_stream); - for (uint32_t j = 0; j < plaintext_len % 64; ++j) - { - encrypted_out[i * 64 + j] = plaintext[i * 64 + j] ^ key_stream[j]; - } - } -} - -static void -to_le64 (uint64_t u, uint8_t *x) -{ - for (unsigned int i = 0; i < 8; ++i) - { - x[i] = u & 0xFF; - u >>= 8; - } -} - -static void -poly1305_clamp (uint8_t *r) -{ - r[3] &= 15; - r[7] &= 15; - r[11] &= 15; - r[15] &= 15; - r[4] &= 252; - r[8] &= 252; - r[12] &= 252; -} - -static void -add256 (uint8_t *h, const uint8_t *c) -{ - uint16_t accumulator = 0; - for (unsigned int i = 0; i < 32; ++i) - { - accumulator += h[i] + c[i]; - h[i] = accumulator & 0xFF; - accumulator >>= 8; - } -} - -static void -sub264 (uint8_t *h, const uint8_t *c) -{ - uint16_t acc = 0; - for (unsigned int i = 0; i < 33; ++i) - { - acc += (255 - h[i]) + c[i]; - h[i] = 255 - (acc & 0xFF); - acc >>= 8; - } -} - -static void -add_shifted (uint8_t *h, const uint64_t c, unsigned int shift) -{ - uint8_t digits[8]; - to_le64 (c, digits); - uint16_t accumulator = 0; - unsigned int i; - for (i = shift; i <= shift + 8 && i < 33; ++i) - { - accumulator += digits[i - shift] + h[i]; - h[i] = accumulator & 0xFF; - accumulator >>= 8; - } - while (i < 33) - { - accumulator += h[i]; - h[i] = accumulator & 0xFF; - accumulator >>= 8; - ++i; - } -} - -static void -mult256 (const uint8_t *a, const uint8_t *b, uint8_t *out) -{ - // Literal long multiplication - for (unsigned int i = 0; i < 33; ++i) - { - out[i] = 0x0; - } - uint32_t a_digits[8]; - uint32_t b_digits[8]; - for (unsigned int i = 0; i < 8; ++i) - { - a_digits[i] = from_le32 (a + i * 4); - b_digits[i] = from_le32 (b + i * 4); - } - for (unsigned int i = 0; i < 8; ++i) - { - for (unsigned int j = 0; j < 8; ++j) - { - uint64_t prod = (uint64_t)a_digits[i] * (uint64_t)b_digits[j]; - add_shifted (out, prod, i * 4 + j * 4); - } - } -} - -static void -shr264_by_130 (const uint8_t *in, uint8_t *out) -{ - for (unsigned int i = 0; i < 16; ++i) - { - out[31 - i] = 0x0; - } - for (unsigned int i = 0; i < 16; ++i) - { - out[i] = (in[i + 16] >> 2) | (in[i + 17] << 6); - } - out[16] = in[32] >> 2; -} - -static bool -iszero256 (const uint8_t *a) -{ - for (unsigned int i = 0; i < 32; ++i) - { - if (a[i] != 0x0) - { - return false; - } - } - return true; -} - -static bool -greater264 (const uint8_t *a, const uint8_t *b) -{ - for (unsigned int i = 0; i < 33; ++i) - { - if (a[32 - i] < b[32 - i]) - { - return false; - } - else if (a[32 - i] > b[32 - i]) - { - return true; - } - } - return false; -} - -static void -modp_264 (uint8_t *in, uint8_t *out) -{ - const uint8_t P[33] = { - 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - }; - uint8_t approx_quotient[32]; - uint8_t approx_dividend[33]; - uint8_t accumulator[33]; - for (unsigned int i = 0; i < 33; ++i) - { - accumulator[i] = in[i]; - } - while (true) - { - shr264_by_130 (accumulator, approx_quotient); - if (iszero256 (approx_quotient)) - { - while (!greater264 (P, accumulator)) - { - sub264 (accumulator, P); - } - for (unsigned int i = 0; i < 32; ++i) - { - out[i] = accumulator[i]; - } - return; - } - mult256 (P, approx_quotient, approx_dividend); - sub264 (accumulator, approx_dividend); - if (greater264 (P, accumulator)) - { - for (unsigned int i = 0; i < 32; ++i) - { - out[i] = accumulator[i]; - } - return; - } - } -} - -static void -poly1305_mac_rolling (const uint8_t *msg, const uint8_t *key, - const uint8_t blocklen, uint8_t *a) -{ - uint8_t r[32]; - for (unsigned int i = 0; i < 32; ++i) - { - r[i] = 0; - } - for (unsigned int i = 0; i < 16; ++i) - { - r[i] = key[i]; - } - - poly1305_clamp (r); - uint8_t n[32]; - for (unsigned int i = blocklen; i < 32; ++i) - { - n[i] = 0x0; - } - for (unsigned int i = 0; i < 16 && i < blocklen; ++i) - { - n[i] = msg[i]; - } - n[blocklen] = 0x1; - add256 (a, n); - uint8_t intermediate[33]; - mult256 (r, a, intermediate); - modp_264 (intermediate, a); -} - -static void -poly1305_mac_init (uint8_t *a) -{ - for (unsigned int i = 0; i < 32; ++i) - { - a[i] = 0x0; - } -} - -static void -poly1305_mac_finish (uint8_t *a, const uint8_t *key) -{ - uint8_t s[32]; - for (unsigned int i = 0; i < 32; ++i) - { - s[i] = 0; - } - for (unsigned int i = 0; i < 16; ++i) - { - s[i] = key[16 + i]; - } - add256 (a, s); -} - -void -tct_aead_chacha20_poly1305 (const uint8_t *aad, const uint64_t aad_len, - const uint8_t *key, const uint8_t *nonce, - const uint8_t *plaintext, - const uint64_t plaintext_len, uint8_t *cipher_out, - uint8_t *mac_out) -{ - uint8_t otk[64]; - cc20_block (key, 0, nonce, otk); - cc20_encrypt (key, 1, nonce, plaintext, plaintext_len, cipher_out); - poly1305_mac_init (mac_out); - uint8_t buf[16]; - uint64_t total_len = 16 + aad_len + plaintext_len; - uint8_t aad_len_le[8], plaintext_len_le[8]; - to_le64 (aad_len, aad_len_le); - to_le64 (plaintext_len, plaintext_len_le); - for (unsigned int i = 0; i < total_len; ++i) - { - if (i < aad_len) - { - buf[i % 16] = aad[i]; - } - else if (i < aad_len + 8) - { - buf[i % 16] = aad_len_le[i - aad_len]; - } - else if (i < aad_len + 8 + plaintext_len) - { - buf[i % 16] = cipher_out[i - aad_len - 8]; - } - else if (i < aad_len + 16 + plaintext_len) - { - buf[i % 16] = plaintext_len_le[i - aad_len - 16 - plaintext_len]; - } - if (i % 16 == 15) - { - poly1305_mac_rolling (buf, otk, 16, mac_out); - } - } - if (total_len % 16 != 0) - { - poly1305_mac_rolling (buf, otk, total_len % 16, mac_out); - } - poly1305_mac_finish (mac_out, otk); -}
M tinycrypt/portable/ed25519.ctinycrypt/min32/ed25519.c

@@ -697,7 +697,7 @@ }

#ifndef TCT_LOWMEM -#include "tinycrypt/portable/ed25519_precompute.h" +#include "tinycrypt/min32/ed25519_precompute.h" static void xB (const uint32_t *k, uint32_t *x, uint32_t *y, uint32_t *z, uint32_t *t)

@@ -907,4 +907,4 @@ xB (sigk, sBx, sBy, sBz, sBt);

scalarmult (chunked, Ax, Ay, hAx, hAy, hAz, hAt); addpoints (Rx, Ry, Rz, Rt, hAx, hAy, hAz, hAt, hAx, hAy, hAz, hAt); return points_eq (sBx, sBy, sBz, sBt, hAx, hAy, hAz, hAt); -}+}
D tinycrypt/x86_64_aarch64/chacha20_poly1305.c

@@ -1,791 +0,0 @@

-#include <stdbool.h> -#include <stdint.h> - -#include "tinycrypt/chacha20_poly1305.h" - -typedef uint32_t dwpacked __attribute__ ((vector_size (16))); -typedef uint8_t bytes16 __attribute__ ((vector_size (16))); - -/* On SSSE3 / NEON the 16- and 8-bit left-rotations each lower to a single - byte permute (pshufb / tbl). On plain SSE2 that permute is emulated poorly - and is markedly slower than shift-or, so fall back to shift-or there. The - 12- and 7-bit rotations are always shift-or. */ -#if defined(__SSSE3__) || defined(__ARM_NEON) || defined(__ARM_NEON__) -static dwpacked -rotl16 (dwpacked x) -{ - bytes16 b = (bytes16)x; - b = __builtin_shufflevector (b, b, 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, - 15, 12, 13); - return (dwpacked)b; -} -static dwpacked -rotl8 (dwpacked x) -{ - bytes16 b = (bytes16)x; - b = __builtin_shufflevector (b, b, 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, - 12, 13, 14); - return (dwpacked)b; -} -#else -static dwpacked -rotl16 (dwpacked x) -{ - return (x << 16) | (x >> 16); -} -static dwpacked -rotl8 (dwpacked x) -{ - return (x << 8) | (x >> 24); -} -#endif - -static dwpacked -rotl_n (dwpacked x, int c) -{ - return (x << c) | (x >> (32 - c)); -} - -static uint32_t -from_le32 (const uint8_t *x) -{ - uint32_t u = x[3]; - u = (u << 8) | x[2]; - u = (u << 8) | x[1]; - return (u << 8) | x[0]; -} - -static void -to_le32 (uint32_t u, uint8_t *x) -{ - for (unsigned int i = 0; i < 4; ++i) - { - x[i] = u & 0xFF; - u >>= 8; - } -} - -/* Quarter-round on whole vectors. The shape is layout agnostic, so the same - macro drives the single-block (row) core and the vertical multi-block - cores below. */ -#define CC20_QR(a, b, c, d) \ - do \ - { \ - a += b; \ - d ^= a; \ - d = rotl16 (d); \ - c += d; \ - b ^= c; \ - b = rotl_n (b, 12); \ - a += b; \ - d ^= a; \ - d = rotl8 (d); \ - c += d; \ - b ^= c; \ - b = rotl_n (b, 7); \ - } \ - while (false) - -static dwpacked -splat (uint32_t v) -{ - return (dwpacked){ v, v, v, v }; -} - -/* Counter/nonce row in the DJB / OpenSSH layout: a 64-bit block counter in - words 12/13 (little-endian) and a 64-bit nonce in words 14/15. This matches - standard ChaCha20 as used by [email protected]. */ -static dwpacked -cc20_counter_row (uint64_t counter, uint32_t n0, uint32_t n1) -{ - return (dwpacked){ (uint32_t)counter, (uint32_t)(counter >> 32), n0, n1 }; -} - -/* One ChaCha20 block; keystream returned in four vectors (row layout). */ -static void -chacha_core (dwpacked s0, dwpacked s1, dwpacked s2, dwpacked s3, - dwpacked out[4]) -{ - dwpacked x0 = s0, x1 = s1, x2 = s2, x3 = s3; - for (uint32_t i = 0; i < 10; ++i) - { - CC20_QR (x0, x1, x2, x3); - x1 = __builtin_shufflevector (x1, x1, 1, 2, 3, 0); - x2 = __builtin_shufflevector (x2, x2, 2, 3, 0, 1); - x3 = __builtin_shufflevector (x3, x3, 3, 0, 1, 2); - CC20_QR (x0, x1, x2, x3); - x1 = __builtin_shufflevector (x1, x1, 3, 0, 1, 2); - x2 = __builtin_shufflevector (x2, x2, 2, 3, 0, 1); - x3 = __builtin_shufflevector (x3, x3, 1, 2, 3, 0); - } - out[0] = x0 + s0; - out[1] = x1 + s1; - out[2] = x2 + s2; - out[3] = x3 + s3; -} - -/* Serializing single-block wrapper, used for the Poly1305 one-time key. */ -static void -cc20_block (const uint8_t *key, const uint64_t counter, const uint8_t *nonce, - uint8_t *state_out) -{ - dwpacked s0 = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; - dwpacked s1 = { from_le32 (key), from_le32 (key + 4), from_le32 (key + 8), - from_le32 (key + 12) }; - dwpacked s2 = { from_le32 (key + 16), from_le32 (key + 20), - from_le32 (key + 24), from_le32 (key + 28) }; - dwpacked s3 - = cc20_counter_row (counter, from_le32 (nonce), from_le32 (nonce + 4)); - dwpacked ks[4]; - chacha_core (s0, s1, s2, s3, ks); - for (unsigned int i = 0; i < 16; ++i) - to_le32 (ks[i / 4][i % 4], state_out + 4 * i); -} - -/* XOR a full 64-byte block; keystream stays in registers. Assumes a - little-endian target (x86-64 / aarch64, the platforms this file targets). */ -static void -cc20_xor64 (const uint8_t *in, const dwpacked ks[4], uint8_t *out) -{ - for (unsigned int k = 0; k < 4; ++k) - { - dwpacked p; - __builtin_memcpy (&p, in + 16 * k, 16); - p ^= ks[k]; - __builtin_memcpy (out + 16 * k, &p, 16); - } -} - -/* Transpose a 4x4 word matrix held in four vectors (rows <-> columns). */ -static void -transpose4 (dwpacked *r0, dwpacked *r1, dwpacked *r2, dwpacked *r3) -{ - dwpacked a0 = __builtin_shufflevector (*r0, *r1, 0, 4, 1, 5); - dwpacked a1 = __builtin_shufflevector (*r0, *r1, 2, 6, 3, 7); - dwpacked a2 = __builtin_shufflevector (*r2, *r3, 0, 4, 1, 5); - dwpacked a3 = __builtin_shufflevector (*r2, *r3, 2, 6, 3, 7); - *r0 = __builtin_shufflevector (a0, a2, 0, 1, 4, 5); - *r1 = __builtin_shufflevector (a0, a2, 2, 3, 6, 7); - *r2 = __builtin_shufflevector (a1, a3, 0, 1, 4, 5); - *r3 = __builtin_shufflevector (a1, a3, 2, 3, 6, 7); -} - -/* Encrypt exactly four blocks held in vertical layout (lane = block) in - v[16]. Removes the per-round diagonalization shuffles the row core needs. */ -static void -cc20_xor_x4 (dwpacked v[16], const uint8_t *pt, uint8_t *out) -{ - dwpacked in[16]; - for (unsigned int k = 0; k < 16; ++k) - in[k] = v[k]; - for (unsigned int r = 0; r < 10; ++r) - { - CC20_QR (v[0], v[4], v[8], v[12]); - CC20_QR (v[1], v[5], v[9], v[13]); - CC20_QR (v[2], v[6], v[10], v[14]); - CC20_QR (v[3], v[7], v[11], v[15]); - CC20_QR (v[0], v[5], v[10], v[15]); - CC20_QR (v[1], v[6], v[11], v[12]); - CC20_QR (v[2], v[7], v[8], v[13]); - CC20_QR (v[3], v[4], v[9], v[14]); - } - for (unsigned int k = 0; k < 16; ++k) - v[k] += in[k]; - transpose4 (&v[0], &v[1], &v[2], &v[3]); - transpose4 (&v[4], &v[5], &v[6], &v[7]); - transpose4 (&v[8], &v[9], &v[10], &v[11]); - transpose4 (&v[12], &v[13], &v[14], &v[15]); - for (unsigned int j = 0; j < 4; ++j) - { - const dwpacked ks[4] = { v[j], v[4 + j], v[8 + j], v[12 + j] }; - cc20_xor64 (pt + 64 * j, ks, out + 64 * j); - } -} - -#ifdef __AVX2__ -typedef uint32_t qwpacked __attribute__ ((vector_size (32))); -typedef uint8_t bytes32 __attribute__ ((vector_size (32))); - -static qwpacked -rotl16_x8 (qwpacked x) -{ - bytes32 b = (bytes32)x; - b = __builtin_shufflevector (b, b, 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, - 15, 12, 13, 18, 19, 16, 17, 22, 23, 20, 21, 26, - 27, 24, 25, 30, 31, 28, 29); - return (qwpacked)b; -} -static qwpacked -rotl8_x8 (qwpacked x) -{ - bytes32 b = (bytes32)x; - b = __builtin_shufflevector (b, b, 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, - 12, 13, 14, 19, 16, 17, 18, 23, 20, 21, 22, 27, - 24, 25, 26, 31, 28, 29, 30); - return (qwpacked)b; -} -static qwpacked -rotl_n_x8 (qwpacked x, int c) -{ - return (x << c) | (x >> (32 - c)); -} - -#define CC20_QR8(a, b, c, d) \ - do \ - { \ - a += b; \ - d ^= a; \ - d = rotl16_x8 (d); \ - c += d; \ - b ^= c; \ - b = rotl_n_x8 (b, 12); \ - a += b; \ - d ^= a; \ - d = rotl8_x8 (d); \ - c += d; \ - b ^= c; \ - b = rotl_n_x8 (b, 7); \ - } \ - while (false) - -/* AVX2 (per-128-bit-lane) building blocks for an 8x8 word transpose. */ -#define CC20_UNPACKLO32(a, b) \ - __builtin_shufflevector (a, b, 0, 8, 1, 9, 4, 12, 5, 13) -#define CC20_UNPACKHI32(a, b) \ - __builtin_shufflevector (a, b, 2, 10, 3, 11, 6, 14, 7, 15) -#define CC20_UNPACKLO64(a, b) \ - __builtin_shufflevector (a, b, 0, 1, 8, 9, 4, 5, 12, 13) -#define CC20_UNPACKHI64(a, b) \ - __builtin_shufflevector (a, b, 2, 3, 10, 11, 6, 7, 14, 15) -#define CC20_PERM128_LO(a, b) \ - __builtin_shufflevector (a, b, 0, 1, 2, 3, 8, 9, 10, 11) -#define CC20_PERM128_HI(a, b) \ - __builtin_shufflevector (a, b, 4, 5, 6, 7, 12, 13, 14, 15) - -static void -transpose8 (qwpacked r[8]) -{ - qwpacked t0 = CC20_UNPACKLO32 (r[0], r[1]), t1 = CC20_UNPACKHI32 (r[0], r[1]); - qwpacked t2 = CC20_UNPACKLO32 (r[2], r[3]), t3 = CC20_UNPACKHI32 (r[2], r[3]); - qwpacked t4 = CC20_UNPACKLO32 (r[4], r[5]), t5 = CC20_UNPACKHI32 (r[4], r[5]); - qwpacked t6 = CC20_UNPACKLO32 (r[6], r[7]), t7 = CC20_UNPACKHI32 (r[6], r[7]); - qwpacked u0 = CC20_UNPACKLO64 (t0, t2), u1 = CC20_UNPACKHI64 (t0, t2); - qwpacked u2 = CC20_UNPACKLO64 (t1, t3), u3 = CC20_UNPACKHI64 (t1, t3); - qwpacked u4 = CC20_UNPACKLO64 (t4, t6), u5 = CC20_UNPACKHI64 (t4, t6); - qwpacked u6 = CC20_UNPACKLO64 (t5, t7), u7 = CC20_UNPACKHI64 (t5, t7); - r[0] = CC20_PERM128_LO (u0, u4); - r[4] = CC20_PERM128_HI (u0, u4); - r[1] = CC20_PERM128_LO (u1, u5); - r[5] = CC20_PERM128_HI (u1, u5); - r[2] = CC20_PERM128_LO (u2, u6); - r[6] = CC20_PERM128_HI (u2, u6); - r[3] = CC20_PERM128_LO (u3, u7); - r[7] = CC20_PERM128_HI (u3, u7); -} - -static qwpacked -splat8 (uint32_t v) -{ - return (qwpacked){ v, v, v, v, v, v, v, v }; -} - -/* Encrypt exactly eight blocks held in vertical layout in v[16]. */ -static void -cc20_xor_x8 (qwpacked v[16], const uint8_t *pt, uint8_t *out) -{ - qwpacked in[16]; - for (unsigned int k = 0; k < 16; ++k) - in[k] = v[k]; - for (unsigned int r = 0; r < 10; ++r) - { - CC20_QR8 (v[0], v[4], v[8], v[12]); - CC20_QR8 (v[1], v[5], v[9], v[13]); - CC20_QR8 (v[2], v[6], v[10], v[14]); - CC20_QR8 (v[3], v[7], v[11], v[15]); - CC20_QR8 (v[0], v[5], v[10], v[15]); - CC20_QR8 (v[1], v[6], v[11], v[12]); - CC20_QR8 (v[2], v[7], v[8], v[13]); - CC20_QR8 (v[3], v[4], v[9], v[14]); - } - for (unsigned int k = 0; k < 16; ++k) - v[k] += in[k]; - /* words 0..7 and 8..15 transposed independently -> lane j is block j */ - transpose8 (&v[0]); - transpose8 (&v[8]); - for (unsigned int j = 0; j < 8; ++j) - { - qwpacked p0, p1; - __builtin_memcpy (&p0, pt + 64 * j, 32); - __builtin_memcpy (&p1, pt + 64 * j + 32, 32); - p0 ^= v[j]; - p1 ^= v[8 + j]; - __builtin_memcpy (out + 64 * j, &p0, 32); - __builtin_memcpy (out + 64 * j + 32, &p1, 32); - } -} -#endif /* __AVX2__ */ - -static void -cc20_encrypt (const uint8_t *key, const uint64_t counter, const uint8_t *nonce, - const uint8_t *plaintext, const uint32_t plaintext_len, - uint8_t *encrypted_out) -{ - /* Constant/key/nonce state is invariant across blocks; build it once. */ - const dwpacked s0 = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; - const dwpacked s1 = { from_le32 (key), from_le32 (key + 4), - from_le32 (key + 8), from_le32 (key + 12) }; - const dwpacked s2 = { from_le32 (key + 16), from_le32 (key + 20), - from_le32 (key + 24), from_le32 (key + 28) }; - const uint32_t n0 = from_le32 (nonce), n1 = from_le32 (nonce + 4); - const uint32_t full = plaintext_len / 64; - uint32_t i = 0; - -#ifdef __AVX2__ - { - const qwpacked b[12] - = { splat8 (s0[0]), splat8 (s0[1]), splat8 (s0[2]), splat8 (s0[3]), - splat8 (s1[0]), splat8 (s1[1]), splat8 (s1[2]), splat8 (s1[3]), - splat8 (s2[0]), splat8 (s2[1]), splat8 (s2[2]), splat8 (s2[3]) }; - const qwpacked bn0 = splat8 (n0), bn1 = splat8 (n1); - for (; i + 8 <= full; i += 8) - { - uint64_t c[8]; - for (unsigned int j = 0; j < 8; ++j) - c[j] = counter + i + j; - qwpacked lo - = { (uint32_t)c[0], (uint32_t)c[1], (uint32_t)c[2], (uint32_t)c[3], - (uint32_t)c[4], (uint32_t)c[5], (uint32_t)c[6], (uint32_t)c[7] }; - qwpacked hi = { (uint32_t)(c[0] >> 32), (uint32_t)(c[1] >> 32), - (uint32_t)(c[2] >> 32), (uint32_t)(c[3] >> 32), - (uint32_t)(c[4] >> 32), (uint32_t)(c[5] >> 32), - (uint32_t)(c[6] >> 32), (uint32_t)(c[7] >> 32) }; - qwpacked v[16] = { b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - b[8], b[9], b[10], b[11], lo, hi, bn0, bn1 }; - cc20_xor_x8 (v, plaintext + 64 * i, encrypted_out + 64 * i); - } - } -#endif - - dwpacked bc[12]; - for (unsigned int j = 0; j < 4; ++j) - { - bc[j] = splat (s0[j]); - bc[4 + j] = splat (s1[j]); - bc[8 + j] = splat (s2[j]); - } - const dwpacked bn0 = splat (n0), bn1 = splat (n1); - for (; i + 4 <= full; i += 4) - { - uint64_t c0 = counter + i, c1 = counter + i + 1, c2 = counter + i + 2, - c3 = counter + i + 3; - dwpacked v[16] - = { bc[0], bc[1], bc[2], bc[3], bc[4], bc[5], bc[6], bc[7], bc[8], - bc[9], bc[10], bc[11], - (dwpacked){ (uint32_t)c0, (uint32_t)c1, (uint32_t)c2, - (uint32_t)c3 }, - (dwpacked){ (uint32_t)(c0 >> 32), (uint32_t)(c1 >> 32), - (uint32_t)(c2 >> 32), (uint32_t)(c3 >> 32) }, - bn0, bn1 }; - cc20_xor_x4 (v, plaintext + 64 * i, encrypted_out + 64 * i); - } - - /* Remaining whole blocks (fewer than the vector width), one at a time. */ - for (; i < full; ++i) - { - dwpacked s3 = cc20_counter_row (counter + i, n0, n1); - dwpacked ks[4]; - chacha_core (s0, s1, s2, s3, ks); - cc20_xor64 (plaintext + 64 * i, ks, encrypted_out + 64 * i); - } - - /* Trailing partial block. */ - if ((plaintext_len % 64) != 0) - { - dwpacked s3 = cc20_counter_row (counter + full, n0, n1); - dwpacked ks[4]; - chacha_core (s0, s1, s2, s3, ks); - uint8_t key_stream[64]; - for (unsigned int k = 0; k < 16; ++k) - to_le32 (ks[k / 4][k % 4], key_stream + 4 * k); - for (uint32_t j = 0; j < plaintext_len % 64; ++j) - encrypted_out[64 * full + j] = plaintext[64 * full + j] ^ key_stream[j]; - } -} - -static void -to_le64 (uint64_t u, uint8_t *x) -{ - for (unsigned int i = 0; i < 8; ++i) - { - x[i] = u & 0xff; - u >>= 8; - } -} - -static uint64_t -from_le64 (const uint8_t *x) -{ - uint64_t u = 0; - for (unsigned int i = 0; i < 8; ++i) - { - u <<= 8; - u |= x[7 - i]; - } - return u; -} - -static void -poly1305_clamp (uint8_t *r) -{ - r[3] &= 15; - r[7] &= 15; - r[11] &= 15; - r[15] &= 15; - r[4] &= 252; - r[8] &= 252; - r[12] &= 252; -} - -static void -add256 (uint64_t *h, const uint64_t *c) -{ - __uint128_t accumulator = 0; - for (unsigned int i = 0; i < 4; ++i) - { - accumulator += (__uint128_t)h[i] + (__uint128_t)c[i]; - h[i] = accumulator & 0xffffffffffffffff; - accumulator >>= 64; - } -} - -static void -mult192 (const uint64_t *a, const uint64_t *b, uint64_t *out) -{ - uint64_t a_int[3], b_int[3]; - __uint128_t intermediate[6] = { - 0, 0, 0, 0, 0, 0, - }; - for (unsigned int i = 0; i < 3; ++i) - { - a_int[i] = a[i]; - b_int[i] = b[i]; - out[i] = 0x0; - out[3 + i] = 0x0; - } - for (unsigned int i = 0; i < 3; ++i) - { - for (unsigned int j = 0; j < 3; ++j) - { - intermediate[i + j] += (__uint128_t)a_int[i] * (__uint128_t)b_int[j]; - intermediate[i + j + 1] += intermediate[i + j] >> 64; - intermediate[i + j] &= 0xffffffffffffffff; - } - } - for (unsigned int k = 0; k < 5; ++k) - { - intermediate[k + 1] += intermediate[k] >> 64; - out[k] = intermediate[k] & 0xffffffffffffffff; - } - out[5] = intermediate[5] & 0xffffffffffffffff; -} - -static void -shr320_by_130 (const uint64_t *in, uint64_t *out) -{ - out[0] = (in[2] >> 2) | (in[3] << 62); - out[1] = (in[3] >> 2) | (in[4] << 62); - out[2] = in[4] >> 2; -} - -/* Fold the bits above 130 into the low 130 via 2^130 = 5 (mod 2^130-5). */ -static void -fold5 (uint64_t *acc) -{ - uint64_t hi[3]; - shr320_by_130 (acc, hi); - uint64_t lo0 = acc[0], lo1 = acc[1], lo2 = acc[2] & 0x3; - __uint128_t c = 0; - uint64_t m[4]; - for (unsigned int i = 0; i < 3; ++i) - { - __uint128_t t = (__uint128_t)hi[i] * 5 + c; - m[i] = (uint64_t)t; - c = t >> 64; - } - m[3] = (uint64_t)c; - __uint128_t s = (__uint128_t)m[0] + lo0; - acc[0] = (uint64_t)s; - c = s >> 64; - s = (__uint128_t)m[1] + lo1 + c; - acc[1] = (uint64_t)s; - c = s >> 64; - s = (__uint128_t)m[2] + lo2 + c; - acc[2] = (uint64_t)s; - c = s >> 64; - s = (__uint128_t)m[3] + c; - acc[3] = (uint64_t)s; - acc[4] = (uint64_t)(s >> 64); -} - -static void -modp320 (uint64_t *in, uint64_t *out) -{ - uint64_t acc[5] = { in[0], in[1], in[2], in[3], in[4] }; - fold5 (acc); - fold5 (acc); /* value now < 2^130 + 80 */ - /* constant-time freeze: if value + 5 carries past bit 130, subtract p */ - __uint128_t c = 5; - __uint128_t s = (__uint128_t)acc[0] + c; - uint64_t t0 = (uint64_t)s; - c = s >> 64; - s = (__uint128_t)acc[1] + c; - uint64_t t1 = (uint64_t)s; - c = s >> 64; - s = (__uint128_t)acc[2] + c; - uint64_t t2 = (uint64_t)s; - uint64_t mask = (uint64_t)0 - ((t2 >> 2) & 1); - out[0] = (t0 & mask) | (acc[0] & ~mask); - out[1] = (t1 & mask) | (acc[1] & ~mask); - out[2] = ((t2 & 0x3) & mask) | (acc[2] & ~mask); - out[3] = 0; -} - -static void -poly1305_mac_rolling (const uint8_t *msg, const uint8_t *key, - const uint8_t blocklen, uint64_t *a) -{ - uint8_t r[32]; - for (unsigned int i = 0; i < 32; ++i) - { - r[i] = 0; - } - for (unsigned int i = 0; i < 16; ++i) - { - r[i] = key[i]; - } - - poly1305_clamp (r); - uint8_t n[32]; - for (unsigned int i = blocklen; i < 32; ++i) - { - n[i] = 0x0; - } - for (unsigned int i = 0; i < 16 && i < blocklen; ++i) - { - n[i] = msg[i]; - } - n[blocklen] = 0x1; - uint64_t n_chunked[4]; - uint64_t r_chunked[4]; - for (unsigned int i = 0; i < 4; ++i) - { - n_chunked[i] = from_le64 (n + 8 * i); - r_chunked[i] = from_le64 (r + 8 * i); - } - add256 (a, n_chunked); - uint64_t intermediate[6]; - mult192 (r_chunked, a, intermediate); - modp320 (intermediate, a); -} - -static void -poly1305_mac_init (uint64_t *a) -{ - for (unsigned int i = 0; i < 4; ++i) - { - a[i] = 0x0; - } -} - -static void -poly1305_mac_finish (uint64_t *a, const uint8_t *key) -{ - uint64_t s[4]; - for (unsigned int i = 2; i < 4; ++i) - { - s[i] = 0; - } - for (unsigned int i = 0; i < 2; ++i) - { - s[i] = from_le64 (key + 16 + 8 * i); - } - add256 (a, s); -} - -bool -tct_aead_chacha20_poly1305_decrypt_and_verify ( - const uint8_t *aad, const uint64_t aad_len, const uint8_t *key, - const uint8_t *nonce, const uint8_t *frame, const uint64_t ciphertext_len, - uint8_t *plaintext_out) -{ - uint8_t otk[64]; - cc20_block (key, 0, nonce, otk); - uint64_t mac_chunked[4]; - poly1305_mac_init (mac_chunked); - uint8_t buf[16]; - uint64_t total_len = 16 + aad_len + ciphertext_len; - uint8_t aad_len_le[8], ciphertext_len_le[8]; - to_le64 (aad_len, aad_len_le); - to_le64 (ciphertext_len, ciphertext_len_le); - for (unsigned int i = 0; i < total_len; ++i) - { - if (i < aad_len) - { - buf[i % 16] = aad[i]; - } - else if (i < aad_len + 8) - { - buf[i % 16] = aad_len_le[i - aad_len]; - } - else if (i < aad_len + 8 + ciphertext_len) - { - buf[i % 16] = frame[i - aad_len - 8]; - } - else if (i < aad_len + 16 + ciphertext_len) - { - buf[i % 16] = ciphertext_len_le[i - aad_len - 8 - ciphertext_len]; - } - if (i % 16 == 15) - { - poly1305_mac_rolling (buf, otk, 16, mac_chunked); - } - } - if (total_len % 16 != 0) - { - poly1305_mac_rolling (buf, otk, total_len % 16, mac_chunked); - } - poly1305_mac_finish (mac_chunked, otk); - if (((from_le64 (frame + ciphertext_len) ^ mac_chunked[0]) - | (from_le64 (frame + ciphertext_len + 8) ^ mac_chunked[1])) - != 0) - { - return false; - } - cc20_encrypt (key, 1, nonce, frame, ciphertext_len, plaintext_out); - return true; -} - -void -tct_aead_chacha20_poly1305_encrypt (const uint8_t *aad, const uint64_t aad_len, - const uint8_t *key, const uint8_t *nonce, - const uint8_t *plaintext, - const uint64_t plaintext_len, - uint8_t *cipher_out, uint8_t *mac_out) -{ - uint8_t otk[64]; - cc20_block (key, 0, nonce, otk); - cc20_encrypt (key, 1, nonce, plaintext, plaintext_len, cipher_out); - uint64_t mac_chunked[4]; - poly1305_mac_init (mac_chunked); - uint8_t buf[16]; - uint64_t total_len = 16 + aad_len + plaintext_len; - uint8_t aad_len_le[8], plaintext_len_le[8]; - to_le64 (aad_len, aad_len_le); - to_le64 (plaintext_len, plaintext_len_le); - for (unsigned int i = 0; i < total_len; ++i) - { - if (i < aad_len) - { - buf[i % 16] = aad[i]; - } - else if (i < aad_len + 8) - { - buf[i % 16] = aad_len_le[i - aad_len]; - } - else if (i < aad_len + 8 + plaintext_len) - { - buf[i % 16] = cipher_out[i - aad_len - 8]; - } - else if (i < aad_len + 16 + plaintext_len) - { - buf[i % 16] = plaintext_len_le[i - aad_len - 8 - plaintext_len]; - } - if (i % 16 == 15) - { - poly1305_mac_rolling (buf, otk, 16, mac_chunked); - } - } - if (total_len % 16 != 0) - { - poly1305_mac_rolling (buf, otk, total_len % 16, mac_chunked); - } - poly1305_mac_finish (mac_chunked, otk); - for (unsigned int i = 0; i < 2; ++i) - { - to_le64 (mac_chunked[i], mac_out + 8 * i); - } -} - -/* ------------------------------------------------------------------ */ -/* [email protected] */ -/* */ -/* Unlike the RFC 8439 AEAD above, OpenSSH's SSH transport cipher */ -/* uses two ChaCha20 keys, encrypts the 4-byte packet length */ -/* separately, and authenticates the raw ciphertext with a plain */ -/* Poly1305 (no AAD, no length framing). The 8-byte nonce is the SSH */ -/* packet sequence number. See PROTOCOL.chacha20poly1305. */ -/* ------------------------------------------------------------------ */ - -/* Poly1305 tag over a contiguous message (the standard construction). */ -static void -poly1305_tag (const uint8_t *otk, const uint8_t *msg, uint64_t len, - uint8_t tag[16]) -{ - uint64_t acc[4]; - poly1305_mac_init (acc); - uint64_t i = 0; - for (; i + 16 <= len; i += 16) - poly1305_mac_rolling (msg + i, otk, 16, acc); - if (i < len) - poly1305_mac_rolling (msg + i, otk, (uint8_t)(len - i), acc); - poly1305_mac_finish (acc, otk); - to_le64 (acc[0], tag); - to_le64 (acc[1], tag + 8); -} - -void -tct_chacha20_poly1305_openssh_seal (const uint8_t *seqnr, const uint8_t *key, - const uint8_t *packet, uint32_t payload_len, - uint8_t *out) -{ - const uint8_t *k_payload = key; /* K_2 */ - const uint8_t *k_length = key + 32; /* K_1 */ - uint8_t otk[64]; - cc20_block (k_payload, 0, seqnr, otk); /* Poly1305 key @ ctr 0 */ - cc20_encrypt (k_length, 0, seqnr, packet, 4, out); /* length @ ctr 0 */ - cc20_encrypt (k_payload, 1, seqnr, packet + 4, payload_len, out + 4); - poly1305_tag (otk, out, 4 + (uint64_t)payload_len, out + 4 + payload_len); -} - -void -tct_chacha20_poly1305_openssh_decrypt_length (const uint8_t *seqnr, - const uint8_t *key, - const uint8_t *enc_len, - uint8_t *len_out) -{ - cc20_encrypt (key + 32, 0, seqnr, enc_len, 4, len_out); /* K_1 @ ctr 0 */ -} - -bool -tct_chacha20_poly1305_openssh_open (const uint8_t *seqnr, const uint8_t *key, - const uint8_t *frame, uint32_t payload_len, - uint8_t *packet_out) -{ - const uint8_t *k_payload = key; /* K_2 */ - const uint8_t *k_length = key + 32; /* K_1 */ - uint8_t otk[64]; - cc20_block (k_payload, 0, seqnr, otk); - const uint64_t ct_len = 4 + (uint64_t)payload_len; - uint8_t tag[16]; - poly1305_tag (otk, frame, ct_len, tag); - /* constant-time tag comparison before touching the payload */ - if (((from_le64 (frame + ct_len) ^ from_le64 (tag)) - | (from_le64 (frame + ct_len + 8) ^ from_le64 (tag + 8))) - != 0) - { - return false; - } - cc20_encrypt (k_length, 0, seqnr, frame, 4, packet_out); - cc20_encrypt (k_payload, 1, seqnr, frame + 4, payload_len, packet_out + 4); - return true; -}
M tinycrypt/x86_64_aarch64/ed25519.ctinycrypt/min64/ed25519.c

@@ -894,7 +894,7 @@ }

#ifndef TCT_LOWMEM -#include "tinycrypt/x86_64_aarch64/ed25519_precompute.h" +#include "tinycrypt/min64/ed25519_precompute.h" static void xB (const uint64_t *k, uint64_t *x, uint64_t *y, uint64_t *z, uint64_t *t)

@@ -1101,4 +1101,4 @@ xB (sigk, sBx, sBy, sBz, sBt);

scalarmult (chunked, Ax, Ay, hAx, hAy, hAz, hAt); addpoints (Rx, Ry, Rz, Rt, hAx, hAy, hAz, hAt, hAx, hAy, hAz, hAt); return points_eq (sBx, sBy, sBz, sBt, hAx, hAy, hAz, hAt); -}+}