summaryrefslogtreecommitdiffstats
path: root/arch/riscv/crypto/sha512-riscv64-glue.c
blob: 43b56a08aeb51af49d00c050e3e16444e3a05c1c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * SHA-512 and SHA-384 using the RISC-V vector crypto extensions
 *
 * Copyright (C) 2023 VRULL GmbH
 * Author: Heiko Stuebner <heiko.stuebner@vrull.eu>
 *
 * Copyright (C) 2023 SiFive, Inc.
 * Author: Jerry Shih <jerry.shih@sifive.com>
 */

#include <asm/simd.h>
#include <asm/vector.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/simd.h>
#include <crypto/sha512_base.h>
#include <linux/linkage.h>
#include <linux/module.h>

/*
 * Note: the asm function only uses the 'state' field of struct sha512_state.
 * It is assumed to be the first field.
 */
asmlinkage void sha512_transform_zvknhb_zvkb(
	struct sha512_state *state, const u8 *data, int num_blocks);

static int riscv64_sha512_update(struct shash_desc *desc, const u8 *data,
				 unsigned int len)
{
	/*
	 * Ensure struct sha512_state begins directly with the SHA-512
	 * 512-bit internal state, as this is what the asm function expects.
	 */
	BUILD_BUG_ON(offsetof(struct sha512_state, state) != 0);

	if (crypto_simd_usable()) {
		kernel_vector_begin();
		sha512_base_do_update(desc, data, len,
				      sha512_transform_zvknhb_zvkb);
		kernel_vector_end();
	} else {
		crypto_sha512_update(desc, data, len);
	}
	return 0;
}

static int riscv64_sha512_finup(struct shash_desc *desc, const u8 *data,
				unsigned int len, u8 *out)
{
	if (crypto_simd_usable()) {
		kernel_vector_begin();
		if (len)
			sha512_base_do_update(desc, data, len,
					      sha512_transform_zvknhb_zvkb);
		sha512_base_do_finalize(desc, sha512_transform_zvknhb_zvkb);
		kernel_vector_end();

		return sha512_base_finish(desc, out);
	}

	return crypto_sha512_finup(desc, data, len, out);
}

static int riscv64_sha512_final(struct shash_desc *desc, u8 *out)
{
	return riscv64_sha512_finup(desc, NULL, 0, out);
}

static int riscv64_sha512_digest(struct shash_desc *desc, const u8 *data,
				 unsigned int len, u8 *out)
{
	return sha512_base_init(desc) ?:
	       riscv64_sha512_finup(desc, data, len, out);
}

static struct shash_alg riscv64_sha512_algs[] = {
	{
		.init = sha512_base_init,
		.update = riscv64_sha512_update,
		.final = riscv64_sha512_final,
		.finup = riscv64_sha512_finup,
		.digest = riscv64_sha512_digest,
		.descsize = sizeof(struct sha512_state),
		.digestsize = SHA512_DIGEST_SIZE,
		.base = {
			.cra_blocksize = SHA512_BLOCK_SIZE,
			.cra_priority = 300,
			.cra_name = "sha512",
			.cra_driver_name = "sha512-riscv64-zvknhb-zvkb",
			.cra_module = THIS_MODULE,
		},
	}, {
		.init = sha384_base_init,
		.update = riscv64_sha512_update,
		.final = riscv64_sha512_final,
		.finup = riscv64_sha512_finup,
		.descsize = sizeof(struct sha512_state),
		.digestsize = SHA384_DIGEST_SIZE,
		.base = {
			.cra_blocksize = SHA384_BLOCK_SIZE,
			.cra_priority = 300,
			.cra_name = "sha384",
			.cra_driver_name = "sha384-riscv64-zvknhb-zvkb",
			.cra_module = THIS_MODULE,
		},
	},
};

static int __init riscv64_sha512_mod_init(void)
{
	if (riscv_isa_extension_available(NULL, ZVKNHB) &&
	    riscv_isa_extension_available(NULL, ZVKB) &&
	    riscv_vector_vlen() >= 128)
		return crypto_register_shashes(riscv64_sha512_algs,
					       ARRAY_SIZE(riscv64_sha512_algs));

	return -ENODEV;
}

static void __exit riscv64_sha512_mod_exit(void)
{
	crypto_unregister_shashes(riscv64_sha512_algs,
				  ARRAY_SIZE(riscv64_sha512_algs));
}

module_init(riscv64_sha512_mod_init);
module_exit(riscv64_sha512_mod_exit);

MODULE_DESCRIPTION("SHA-512 (RISC-V accelerated)");
MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@vrull.eu>");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CRYPTO("sha512");
MODULE_ALIAS_CRYPTO("sha384");