brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · 8757f73 Raw
133 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2022-2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.4 */5 6#include <linux/compiler.h>7#include <tools/le_byteshift.h>8#include <sys/random.h>9#include <sys/auxv.h>10#include <string.h>11#include <stdint.h>12#include <stdbool.h>13#include "../kselftest.h"14 15#if defined(__aarch64__)16static bool cpu_has_capabilities(void)17{18	return getauxval(AT_HWCAP) & HWCAP_ASIMD;19}20#elif defined(__s390x__)21static bool cpu_has_capabilities(void)22{23	return getauxval(AT_HWCAP) & HWCAP_S390_VXRS;24}25#else26static bool cpu_has_capabilities(void)27{28	return true;29}30#endif31 32static uint32_t rol32(uint32_t word, unsigned int shift)33{34	return (word << (shift & 31)) | (word >> ((-shift) & 31));35}36 37static void reference_chacha20_blocks(uint8_t *dst_bytes, const uint32_t *key, uint32_t *counter, size_t nblocks)38{39	uint32_t s[16] = {40		0x61707865U, 0x3320646eU, 0x79622d32U, 0x6b206574U,41		key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7],42		counter[0], counter[1], 0, 043	};44 45	while (nblocks--) {46		uint32_t x[16];47		memcpy(x, s, sizeof(x));48		for (unsigned int r = 0; r < 20; r += 2) {49		#define QR(a, b, c, d) ( \50			x[a] += x[b], \51			x[d] = rol32(x[d] ^ x[a], 16), \52			x[c] += x[d], \53			x[b] = rol32(x[b] ^ x[c], 12), \54			x[a] += x[b], \55			x[d] = rol32(x[d] ^ x[a], 8), \56			x[c] += x[d], \57			x[b] = rol32(x[b] ^ x[c], 7))58 59			QR(0, 4, 8, 12);60			QR(1, 5, 9, 13);61			QR(2, 6, 10, 14);62			QR(3, 7, 11, 15);63			QR(0, 5, 10, 15);64			QR(1, 6, 11, 12);65			QR(2, 7, 8, 13);66			QR(3, 4, 9, 14);67		}68		for (unsigned int i = 0; i < 16; ++i, dst_bytes += sizeof(uint32_t))69			put_unaligned_le32(x[i] + s[i], dst_bytes);70		if (!++s[12])71			++s[13];72	}73	counter[0] = s[12];74	counter[1] = s[13];75}76 77void __weak __arch_chacha20_blocks_nostack(uint8_t *dst_bytes, const uint32_t *key, uint32_t *counter, size_t nblocks)78{79	ksft_exit_skip("Not implemented on architecture\n");80}81 82int main(int argc, char *argv[])83{84	enum { TRIALS = 1000, BLOCKS = 128, BLOCK_SIZE = 64 };85	uint32_t key[8], counter1[2], counter2[2];86	uint8_t output1[BLOCK_SIZE * BLOCKS], output2[BLOCK_SIZE * BLOCKS];87 88	ksft_print_header();89	if (!cpu_has_capabilities())90		ksft_exit_skip("Required CPU capabilities missing\n");91	ksft_set_plan(1);92 93	for (unsigned int trial = 0; trial < TRIALS; ++trial) {94		if (getrandom(key, sizeof(key), 0) != sizeof(key))95			ksft_exit_skip("getrandom() failed unexpectedly\n");96		memset(counter1, 0, sizeof(counter1));97		reference_chacha20_blocks(output1, key, counter1, BLOCKS);98		for (unsigned int split = 0; split < BLOCKS; ++split) {99			memset(output2, 'X', sizeof(output2));100			memset(counter2, 0, sizeof(counter2));101			if (split)102				__arch_chacha20_blocks_nostack(output2, key, counter2, split);103			__arch_chacha20_blocks_nostack(output2 + split * BLOCK_SIZE, key, counter2, BLOCKS - split);104			if (memcmp(output1, output2, sizeof(output1)))105				ksft_exit_fail_msg("Main loop outputs do not match on trial %u, split %u\n", trial, split);106			if (memcmp(counter1, counter2, sizeof(counter1)))107				ksft_exit_fail_msg("Main loop counters do not match on trial %u, split %u\n", trial, split);108		}109	}110	memset(counter1, 0, sizeof(counter1));111	counter1[0] = (uint32_t)-BLOCKS + 2;112	memset(counter2, 0, sizeof(counter2));113	counter2[0] = (uint32_t)-BLOCKS + 2;114 115	reference_chacha20_blocks(output1, key, counter1, BLOCKS);116	__arch_chacha20_blocks_nostack(output2, key, counter2, BLOCKS);117	if (memcmp(output1, output2, sizeof(output1)))118		ksft_exit_fail_msg("Block limit outputs do not match after first round\n");119	if (memcmp(counter1, counter2, sizeof(counter1)))120		ksft_exit_fail_msg("Block limit counters do not match after first round\n");121 122	reference_chacha20_blocks(output1, key, counter1, BLOCKS);123	__arch_chacha20_blocks_nostack(output2, key, counter2, BLOCKS);124	if (memcmp(output1, output2, sizeof(output1)))125		ksft_exit_fail_msg("Block limit outputs do not match after second round\n");126	if (memcmp(counter1, counter2, sizeof(counter1)))127		ksft_exit_fail_msg("Block limit counters do not match after second round\n");128 129	ksft_test_result_pass("chacha: PASS\n");130	ksft_exit_pass();131	return 0;132}133