xref: /linux-6.15/crypto/zstd.c (revision d6ebf528)
1d28fc3dbSNick Terrell /*
2d28fc3dbSNick Terrell  * Cryptographic API.
3d28fc3dbSNick Terrell  *
4d28fc3dbSNick Terrell  * Copyright (c) 2017-present, Facebook, Inc.
5d28fc3dbSNick Terrell  *
6d28fc3dbSNick Terrell  * This program is free software; you can redistribute it and/or modify it
7d28fc3dbSNick Terrell  * under the terms of the GNU General Public License version 2 as published by
8d28fc3dbSNick Terrell  * the Free Software Foundation.
9d28fc3dbSNick Terrell  *
10d28fc3dbSNick Terrell  * This program is distributed in the hope that it will be useful, but WITHOUT
11d28fc3dbSNick Terrell  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12d28fc3dbSNick Terrell  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13d28fc3dbSNick Terrell  * more details.
14d28fc3dbSNick Terrell  */
15d28fc3dbSNick Terrell #include <linux/crypto.h>
16d28fc3dbSNick Terrell #include <linux/init.h>
17d28fc3dbSNick Terrell #include <linux/interrupt.h>
18d28fc3dbSNick Terrell #include <linux/mm.h>
19d28fc3dbSNick Terrell #include <linux/module.h>
20d28fc3dbSNick Terrell #include <linux/net.h>
21d28fc3dbSNick Terrell #include <linux/vmalloc.h>
22d28fc3dbSNick Terrell #include <linux/zstd.h>
23d28fc3dbSNick Terrell #include <crypto/internal/scompress.h>
24d28fc3dbSNick Terrell 
25d28fc3dbSNick Terrell 
26d28fc3dbSNick Terrell #define ZSTD_DEF_LEVEL	3
27d28fc3dbSNick Terrell 
28d28fc3dbSNick Terrell struct zstd_ctx {
29d28fc3dbSNick Terrell 	ZSTD_CCtx *cctx;
30d28fc3dbSNick Terrell 	ZSTD_DCtx *dctx;
31d28fc3dbSNick Terrell 	void *cwksp;
32d28fc3dbSNick Terrell 	void *dwksp;
33d28fc3dbSNick Terrell };
34d28fc3dbSNick Terrell 
35d28fc3dbSNick Terrell static ZSTD_parameters zstd_params(void)
36d28fc3dbSNick Terrell {
37d28fc3dbSNick Terrell 	return ZSTD_getParams(ZSTD_DEF_LEVEL, 0, 0);
38d28fc3dbSNick Terrell }
39d28fc3dbSNick Terrell 
40d28fc3dbSNick Terrell static int zstd_comp_init(struct zstd_ctx *ctx)
41d28fc3dbSNick Terrell {
42d28fc3dbSNick Terrell 	int ret = 0;
43d28fc3dbSNick Terrell 	const ZSTD_parameters params = zstd_params();
44d28fc3dbSNick Terrell 	const size_t wksp_size = ZSTD_CCtxWorkspaceBound(params.cParams);
45d28fc3dbSNick Terrell 
46d28fc3dbSNick Terrell 	ctx->cwksp = vzalloc(wksp_size);
47d28fc3dbSNick Terrell 	if (!ctx->cwksp) {
48d28fc3dbSNick Terrell 		ret = -ENOMEM;
49d28fc3dbSNick Terrell 		goto out;
50d28fc3dbSNick Terrell 	}
51d28fc3dbSNick Terrell 
52d28fc3dbSNick Terrell 	ctx->cctx = ZSTD_initCCtx(ctx->cwksp, wksp_size);
53d28fc3dbSNick Terrell 	if (!ctx->cctx) {
54d28fc3dbSNick Terrell 		ret = -EINVAL;
55d28fc3dbSNick Terrell 		goto out_free;
56d28fc3dbSNick Terrell 	}
57d28fc3dbSNick Terrell out:
58d28fc3dbSNick Terrell 	return ret;
59d28fc3dbSNick Terrell out_free:
60d28fc3dbSNick Terrell 	vfree(ctx->cwksp);
61d28fc3dbSNick Terrell 	goto out;
62d28fc3dbSNick Terrell }
63d28fc3dbSNick Terrell 
64d28fc3dbSNick Terrell static int zstd_decomp_init(struct zstd_ctx *ctx)
65d28fc3dbSNick Terrell {
66d28fc3dbSNick Terrell 	int ret = 0;
67d28fc3dbSNick Terrell 	const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
68d28fc3dbSNick Terrell 
69d28fc3dbSNick Terrell 	ctx->dwksp = vzalloc(wksp_size);
70d28fc3dbSNick Terrell 	if (!ctx->dwksp) {
71d28fc3dbSNick Terrell 		ret = -ENOMEM;
72d28fc3dbSNick Terrell 		goto out;
73d28fc3dbSNick Terrell 	}
74d28fc3dbSNick Terrell 
75d28fc3dbSNick Terrell 	ctx->dctx = ZSTD_initDCtx(ctx->dwksp, wksp_size);
76d28fc3dbSNick Terrell 	if (!ctx->dctx) {
77d28fc3dbSNick Terrell 		ret = -EINVAL;
78d28fc3dbSNick Terrell 		goto out_free;
79d28fc3dbSNick Terrell 	}
80d28fc3dbSNick Terrell out:
81d28fc3dbSNick Terrell 	return ret;
82d28fc3dbSNick Terrell out_free:
83d28fc3dbSNick Terrell 	vfree(ctx->dwksp);
84d28fc3dbSNick Terrell 	goto out;
85d28fc3dbSNick Terrell }
86d28fc3dbSNick Terrell 
87d28fc3dbSNick Terrell static void zstd_comp_exit(struct zstd_ctx *ctx)
88d28fc3dbSNick Terrell {
89d28fc3dbSNick Terrell 	vfree(ctx->cwksp);
90d28fc3dbSNick Terrell 	ctx->cwksp = NULL;
91d28fc3dbSNick Terrell 	ctx->cctx = NULL;
92d28fc3dbSNick Terrell }
93d28fc3dbSNick Terrell 
94d28fc3dbSNick Terrell static void zstd_decomp_exit(struct zstd_ctx *ctx)
95d28fc3dbSNick Terrell {
96d28fc3dbSNick Terrell 	vfree(ctx->dwksp);
97d28fc3dbSNick Terrell 	ctx->dwksp = NULL;
98d28fc3dbSNick Terrell 	ctx->dctx = NULL;
99d28fc3dbSNick Terrell }
100d28fc3dbSNick Terrell 
101d28fc3dbSNick Terrell static int __zstd_init(void *ctx)
102d28fc3dbSNick Terrell {
103d28fc3dbSNick Terrell 	int ret;
104d28fc3dbSNick Terrell 
105d28fc3dbSNick Terrell 	ret = zstd_comp_init(ctx);
106d28fc3dbSNick Terrell 	if (ret)
107d28fc3dbSNick Terrell 		return ret;
108d28fc3dbSNick Terrell 	ret = zstd_decomp_init(ctx);
109d28fc3dbSNick Terrell 	if (ret)
110d28fc3dbSNick Terrell 		zstd_comp_exit(ctx);
111d28fc3dbSNick Terrell 	return ret;
112d28fc3dbSNick Terrell }
113d28fc3dbSNick Terrell 
114d28fc3dbSNick Terrell static void *zstd_alloc_ctx(struct crypto_scomp *tfm)
115d28fc3dbSNick Terrell {
116d28fc3dbSNick Terrell 	int ret;
117d28fc3dbSNick Terrell 	struct zstd_ctx *ctx;
118d28fc3dbSNick Terrell 
119d28fc3dbSNick Terrell 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
120d28fc3dbSNick Terrell 	if (!ctx)
121d28fc3dbSNick Terrell 		return ERR_PTR(-ENOMEM);
122d28fc3dbSNick Terrell 
123d28fc3dbSNick Terrell 	ret = __zstd_init(ctx);
124d28fc3dbSNick Terrell 	if (ret) {
125d28fc3dbSNick Terrell 		kfree(ctx);
126d28fc3dbSNick Terrell 		return ERR_PTR(ret);
127d28fc3dbSNick Terrell 	}
128d28fc3dbSNick Terrell 
129d28fc3dbSNick Terrell 	return ctx;
130d28fc3dbSNick Terrell }
131d28fc3dbSNick Terrell 
132d28fc3dbSNick Terrell static int zstd_init(struct crypto_tfm *tfm)
133d28fc3dbSNick Terrell {
134d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
135d28fc3dbSNick Terrell 
136d28fc3dbSNick Terrell 	return __zstd_init(ctx);
137d28fc3dbSNick Terrell }
138d28fc3dbSNick Terrell 
139d28fc3dbSNick Terrell static void __zstd_exit(void *ctx)
140d28fc3dbSNick Terrell {
141d28fc3dbSNick Terrell 	zstd_comp_exit(ctx);
142d28fc3dbSNick Terrell 	zstd_decomp_exit(ctx);
143d28fc3dbSNick Terrell }
144d28fc3dbSNick Terrell 
145d28fc3dbSNick Terrell static void zstd_free_ctx(struct crypto_scomp *tfm, void *ctx)
146d28fc3dbSNick Terrell {
147d28fc3dbSNick Terrell 	__zstd_exit(ctx);
148d28fc3dbSNick Terrell 	kzfree(ctx);
149d28fc3dbSNick Terrell }
150d28fc3dbSNick Terrell 
151d28fc3dbSNick Terrell static void zstd_exit(struct crypto_tfm *tfm)
152d28fc3dbSNick Terrell {
153d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
154d28fc3dbSNick Terrell 
155d28fc3dbSNick Terrell 	__zstd_exit(ctx);
156d28fc3dbSNick Terrell }
157d28fc3dbSNick Terrell 
158d28fc3dbSNick Terrell static int __zstd_compress(const u8 *src, unsigned int slen,
159d28fc3dbSNick Terrell 			   u8 *dst, unsigned int *dlen, void *ctx)
160d28fc3dbSNick Terrell {
161d28fc3dbSNick Terrell 	size_t out_len;
162d28fc3dbSNick Terrell 	struct zstd_ctx *zctx = ctx;
163d28fc3dbSNick Terrell 	const ZSTD_parameters params = zstd_params();
164d28fc3dbSNick Terrell 
165d28fc3dbSNick Terrell 	out_len = ZSTD_compressCCtx(zctx->cctx, dst, *dlen, src, slen, params);
166d28fc3dbSNick Terrell 	if (ZSTD_isError(out_len))
167d28fc3dbSNick Terrell 		return -EINVAL;
168d28fc3dbSNick Terrell 	*dlen = out_len;
169d28fc3dbSNick Terrell 	return 0;
170d28fc3dbSNick Terrell }
171d28fc3dbSNick Terrell 
172d28fc3dbSNick Terrell static int zstd_compress(struct crypto_tfm *tfm, const u8 *src,
173d28fc3dbSNick Terrell 			 unsigned int slen, u8 *dst, unsigned int *dlen)
174d28fc3dbSNick Terrell {
175d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
176d28fc3dbSNick Terrell 
177d28fc3dbSNick Terrell 	return __zstd_compress(src, slen, dst, dlen, ctx);
178d28fc3dbSNick Terrell }
179d28fc3dbSNick Terrell 
180d28fc3dbSNick Terrell static int zstd_scompress(struct crypto_scomp *tfm, const u8 *src,
181d28fc3dbSNick Terrell 			  unsigned int slen, u8 *dst, unsigned int *dlen,
182d28fc3dbSNick Terrell 			  void *ctx)
183d28fc3dbSNick Terrell {
184d28fc3dbSNick Terrell 	return __zstd_compress(src, slen, dst, dlen, ctx);
185d28fc3dbSNick Terrell }
186d28fc3dbSNick Terrell 
187d28fc3dbSNick Terrell static int __zstd_decompress(const u8 *src, unsigned int slen,
188d28fc3dbSNick Terrell 			     u8 *dst, unsigned int *dlen, void *ctx)
189d28fc3dbSNick Terrell {
190d28fc3dbSNick Terrell 	size_t out_len;
191d28fc3dbSNick Terrell 	struct zstd_ctx *zctx = ctx;
192d28fc3dbSNick Terrell 
193d28fc3dbSNick Terrell 	out_len = ZSTD_decompressDCtx(zctx->dctx, dst, *dlen, src, slen);
194d28fc3dbSNick Terrell 	if (ZSTD_isError(out_len))
195d28fc3dbSNick Terrell 		return -EINVAL;
196d28fc3dbSNick Terrell 	*dlen = out_len;
197d28fc3dbSNick Terrell 	return 0;
198d28fc3dbSNick Terrell }
199d28fc3dbSNick Terrell 
200d28fc3dbSNick Terrell static int zstd_decompress(struct crypto_tfm *tfm, const u8 *src,
201d28fc3dbSNick Terrell 			   unsigned int slen, u8 *dst, unsigned int *dlen)
202d28fc3dbSNick Terrell {
203d28fc3dbSNick Terrell 	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
204d28fc3dbSNick Terrell 
205d28fc3dbSNick Terrell 	return __zstd_decompress(src, slen, dst, dlen, ctx);
206d28fc3dbSNick Terrell }
207d28fc3dbSNick Terrell 
208d28fc3dbSNick Terrell static int zstd_sdecompress(struct crypto_scomp *tfm, const u8 *src,
209d28fc3dbSNick Terrell 			    unsigned int slen, u8 *dst, unsigned int *dlen,
210d28fc3dbSNick Terrell 			    void *ctx)
211d28fc3dbSNick Terrell {
212d28fc3dbSNick Terrell 	return __zstd_decompress(src, slen, dst, dlen, ctx);
213d28fc3dbSNick Terrell }
214d28fc3dbSNick Terrell 
215d28fc3dbSNick Terrell static struct crypto_alg alg = {
216d28fc3dbSNick Terrell 	.cra_name		= "zstd",
217*d6ebf528SEric Biggers 	.cra_driver_name	= "zstd-generic",
218d28fc3dbSNick Terrell 	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
219d28fc3dbSNick Terrell 	.cra_ctxsize		= sizeof(struct zstd_ctx),
220d28fc3dbSNick Terrell 	.cra_module		= THIS_MODULE,
221d28fc3dbSNick Terrell 	.cra_init		= zstd_init,
222d28fc3dbSNick Terrell 	.cra_exit		= zstd_exit,
223d28fc3dbSNick Terrell 	.cra_u			= { .compress = {
224d28fc3dbSNick Terrell 	.coa_compress		= zstd_compress,
225d28fc3dbSNick Terrell 	.coa_decompress		= zstd_decompress } }
226d28fc3dbSNick Terrell };
227d28fc3dbSNick Terrell 
228d28fc3dbSNick Terrell static struct scomp_alg scomp = {
229d28fc3dbSNick Terrell 	.alloc_ctx		= zstd_alloc_ctx,
230d28fc3dbSNick Terrell 	.free_ctx		= zstd_free_ctx,
231d28fc3dbSNick Terrell 	.compress		= zstd_scompress,
232d28fc3dbSNick Terrell 	.decompress		= zstd_sdecompress,
233d28fc3dbSNick Terrell 	.base			= {
234d28fc3dbSNick Terrell 		.cra_name	= "zstd",
235d28fc3dbSNick Terrell 		.cra_driver_name = "zstd-scomp",
236d28fc3dbSNick Terrell 		.cra_module	 = THIS_MODULE,
237d28fc3dbSNick Terrell 	}
238d28fc3dbSNick Terrell };
239d28fc3dbSNick Terrell 
240d28fc3dbSNick Terrell static int __init zstd_mod_init(void)
241d28fc3dbSNick Terrell {
242d28fc3dbSNick Terrell 	int ret;
243d28fc3dbSNick Terrell 
244d28fc3dbSNick Terrell 	ret = crypto_register_alg(&alg);
245d28fc3dbSNick Terrell 	if (ret)
246d28fc3dbSNick Terrell 		return ret;
247d28fc3dbSNick Terrell 
248d28fc3dbSNick Terrell 	ret = crypto_register_scomp(&scomp);
249d28fc3dbSNick Terrell 	if (ret)
250d28fc3dbSNick Terrell 		crypto_unregister_alg(&alg);
251d28fc3dbSNick Terrell 
252d28fc3dbSNick Terrell 	return ret;
253d28fc3dbSNick Terrell }
254d28fc3dbSNick Terrell 
255d28fc3dbSNick Terrell static void __exit zstd_mod_fini(void)
256d28fc3dbSNick Terrell {
257d28fc3dbSNick Terrell 	crypto_unregister_alg(&alg);
258d28fc3dbSNick Terrell 	crypto_unregister_scomp(&scomp);
259d28fc3dbSNick Terrell }
260d28fc3dbSNick Terrell 
261c4741b23SEric Biggers subsys_initcall(zstd_mod_init);
262d28fc3dbSNick Terrell module_exit(zstd_mod_fini);
263d28fc3dbSNick Terrell 
264d28fc3dbSNick Terrell MODULE_LICENSE("GPL");
265d28fc3dbSNick Terrell MODULE_DESCRIPTION("Zstd Compression Algorithm");
266d28fc3dbSNick Terrell MODULE_ALIAS_CRYPTO("zstd");
267