File Index
Files and directories
Sign in
FILE

vdso_test_chacha.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/vDSO/vdso_test_chacha.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  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#else
 26static bool cpu_has_capabilities(void)
 27{
 28	return true;
 29}
 30#endif
 31
 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, 0
 43	};
 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_test_result_skip("Not implemented on architecture\n");
 80	ksft_finished();
 81}
 82
 83int main(int argc, char *argv[])
 84{
 85	enum { TRIALS = 1000, BLOCKS = 128, BLOCK_SIZE = 64 };
 86	uint32_t key[8], counter1[2], counter2[2];
 87	uint8_t output1[BLOCK_SIZE * BLOCKS], output2[BLOCK_SIZE * BLOCKS];
 88
 89	ksft_print_header();
 90	if (!cpu_has_capabilities())
 91		ksft_exit_skip("Required CPU capabilities missing\n");
 92	ksft_set_plan(1);
 93
 94	for (unsigned int trial = 0; trial < TRIALS; ++trial) {
 95		if (getrandom(key, sizeof(key), 0) != sizeof(key))
 96			ksft_exit_skip("getrandom() failed unexpectedly\n");
 97		memset(counter1, 0, sizeof(counter1));
 98		reference_chacha20_blocks(output1, key, counter1, BLOCKS);
 99		for (unsigned int split = 0; split < BLOCKS; ++split) {
100			memset(output2, 'X', sizeof(output2));
101			memset(counter2, 0, sizeof(counter2));
102			if (split)
103				__arch_chacha20_blocks_nostack(output2, key, counter2, split);
104			__arch_chacha20_blocks_nostack(output2 + split * BLOCK_SIZE, key, counter2, BLOCKS - split);
105			if (memcmp(output1, output2, sizeof(output1)))
106				ksft_exit_fail_msg("Main loop outputs do not match on trial %u, split %u\n", trial, split);
107			if (memcmp(counter1, counter2, sizeof(counter1)))
108				ksft_exit_fail_msg("Main loop counters do not match on trial %u, split %u\n", trial, split);
109		}
110	}
111	memset(counter1, 0, sizeof(counter1));
112	counter1[0] = (uint32_t)-BLOCKS + 2;
113	memset(counter2, 0, sizeof(counter2));
114	counter2[0] = (uint32_t)-BLOCKS + 2;
115
116	reference_chacha20_blocks(output1, key, counter1, BLOCKS);
117	__arch_chacha20_blocks_nostack(output2, key, counter2, BLOCKS);
118	if (memcmp(output1, output2, sizeof(output1)))
119		ksft_exit_fail_msg("Block limit outputs do not match after first round\n");
120	if (memcmp(counter1, counter2, sizeof(counter1)))
121		ksft_exit_fail_msg("Block limit counters do not match after first round\n");
122
123	reference_chacha20_blocks(output1, key, counter1, BLOCKS);
124	__arch_chacha20_blocks_nostack(output2, key, counter2, BLOCKS);
125	if (memcmp(output1, output2, sizeof(output1)))
126		ksft_exit_fail_msg("Block limit outputs do not match after second round\n");
127	if (memcmp(counter1, counter2, sizeof(counter1)))
128		ksft_exit_fail_msg("Block limit counters do not match after second round\n");
129
130	ksft_test_result_pass("chacha: PASS\n");
131	ksft_exit_pass();
132	return 0;
133}
~/ Read-only file preview.