1From 308795a7713ca6fcd468b60fba9a2fca99cee6a0 Mon Sep 17 00:00:00 2001
2From: Nick Terrell <terrelln@fb.com>
3Date: Wed, 2 Aug 2017 18:02:13 -0700
4Subject: [PATCH v5 5/5] crypto: Add zstd support
5
6Adds zstd support to crypto and scompress. Only supports the default
7level.
8
9Signed-off-by: Nick Terrell <terrelln@fb.com>
10---
11 crypto/Kconfig   |   9 ++
12 crypto/Makefile  |   1 +
13 crypto/testmgr.c |  10 +++
14 crypto/testmgr.h |  71 +++++++++++++++
15 crypto/zstd.c    | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
16 5 files changed, 356 insertions(+)
17 create mode 100644 crypto/zstd.c
18
19diff --git a/crypto/Kconfig b/crypto/Kconfig
20index caa770e..4fc3936 100644
21--- a/crypto/Kconfig
22+++ b/crypto/Kconfig
23@@ -1662,6 +1662,15 @@ config CRYPTO_LZ4HC
24 	help
25 	  This is the LZ4 high compression mode algorithm.
26
27+config CRYPTO_ZSTD
28+	tristate "Zstd compression algorithm"
29+	select CRYPTO_ALGAPI
30+	select CRYPTO_ACOMP2
31+	select ZSTD_COMPRESS
32+	select ZSTD_DECOMPRESS
33+	help
34+	  This is the zstd algorithm.
35+
36 comment "Random Number Generation"
37
38 config CRYPTO_ANSI_CPRNG
39diff --git a/crypto/Makefile b/crypto/Makefile
40index d41f033..b22e1e8 100644
41--- a/crypto/Makefile
42+++ b/crypto/Makefile
43@@ -133,6 +133,7 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
44 obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
45 obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
46 obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
47+obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
48
49 ecdh_generic-y := ecc.o
50 ecdh_generic-y += ecdh.o
51diff --git a/crypto/testmgr.c b/crypto/testmgr.c
52index 7125ba3..8a124d3 100644
53--- a/crypto/testmgr.c
54+++ b/crypto/testmgr.c
55@@ -3603,6 +3603,16 @@ static const struct alg_test_desc alg_test_descs[] = {
56 				.decomp = __VECS(zlib_deflate_decomp_tv_template)
57 			}
58 		}
59+	}, {
60+		.alg = "zstd",
61+		.test = alg_test_comp,
62+		.fips_allowed = 1,
63+		.suite = {
64+			.comp = {
65+				.comp = __VECS(zstd_comp_tv_template),
66+				.decomp = __VECS(zstd_decomp_tv_template)
67+			}
68+		}
69 	}
70 };
71
72diff --git a/crypto/testmgr.h b/crypto/testmgr.h
73index 6ceb0e2..e6b5920 100644
74--- a/crypto/testmgr.h
75+++ b/crypto/testmgr.h
76@@ -34631,4 +34631,75 @@ static const struct comp_testvec lz4hc_decomp_tv_template[] = {
77 	},
78 };
79
80+static const struct comp_testvec zstd_comp_tv_template[] = {
81+	{
82+		.inlen	= 68,
83+		.outlen	= 39,
84+		.input	= "The algorithm is zstd. "
85+			  "The algorithm is zstd. "
86+			  "The algorithm is zstd.",
87+		.output	= "\x28\xb5\x2f\xfd\x00\x50\xf5\x00\x00\xb8\x54\x68\x65"
88+			  "\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x69\x73"
89+			  "\x20\x7a\x73\x74\x64\x2e\x20\x01\x00\x55\x73\x36\x01"
90+			  ,
91+	},
92+	{
93+		.inlen	= 244,
94+		.outlen	= 151,
95+		.input	= "zstd, short for Zstandard, is a fast lossless "
96+			  "compression algorithm, targeting real-time "
97+			  "compression scenarios at zlib-level and better "
98+			  "compression ratios. The zstd compression library "
99+			  "provides in-memory compression and decompression "
100+			  "functions.",
101+		.output	= "\x28\xb5\x2f\xfd\x00\x50\x75\x04\x00\x42\x4b\x1e\x17"
102+			  "\x90\x81\x31\x00\xf2\x2f\xe4\x36\xc9\xef\x92\x88\x32"
103+			  "\xc9\xf2\x24\x94\xd8\x68\x9a\x0f\x00\x0c\xc4\x31\x6f"
104+			  "\x0d\x0c\x38\xac\x5c\x48\x03\xcd\x63\x67\xc0\xf3\xad"
105+			  "\x4e\x90\xaa\x78\xa0\xa4\xc5\x99\xda\x2f\xb6\x24\x60"
106+			  "\xe2\x79\x4b\xaa\xb6\x6b\x85\x0b\xc9\xc6\x04\x66\x86"
107+			  "\xe2\xcc\xe2\x25\x3f\x4f\x09\xcd\xb8\x9d\xdb\xc1\x90"
108+			  "\xa9\x11\xbc\x35\x44\x69\x2d\x9c\x64\x4f\x13\x31\x64"
109+			  "\xcc\xfb\x4d\x95\x93\x86\x7f\x33\x7f\x1a\xef\xe9\x30"
110+			  "\xf9\x67\xa1\x94\x0a\x69\x0f\x60\xcd\xc3\xab\x99\xdc"
111+			  "\x42\xed\x97\x05\x00\x33\xc3\x15\x95\x3a\x06\xa0\x0e"
112+			  "\x20\xa9\x0e\x82\xb9\x43\x45\x01",
113+	},
114+};
115+
116+static const struct comp_testvec zstd_decomp_tv_template[] = {
117+	{
118+		.inlen	= 43,
119+		.outlen	= 68,
120+		.input	= "\x28\xb5\x2f\xfd\x04\x50\xf5\x00\x00\xb8\x54\x68\x65"
121+			  "\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x69\x73"
122+			  "\x20\x7a\x73\x74\x64\x2e\x20\x01\x00\x55\x73\x36\x01"
123+			  "\x6b\xf4\x13\x35",
124+		.output	= "The algorithm is zstd. "
125+			  "The algorithm is zstd. "
126+			  "The algorithm is zstd.",
127+	},
128+	{
129+		.inlen	= 155,
130+		.outlen	= 244,
131+		.input	= "\x28\xb5\x2f\xfd\x04\x50\x75\x04\x00\x42\x4b\x1e\x17"
132+			  "\x90\x81\x31\x00\xf2\x2f\xe4\x36\xc9\xef\x92\x88\x32"
133+			  "\xc9\xf2\x24\x94\xd8\x68\x9a\x0f\x00\x0c\xc4\x31\x6f"
134+			  "\x0d\x0c\x38\xac\x5c\x48\x03\xcd\x63\x67\xc0\xf3\xad"
135+			  "\x4e\x90\xaa\x78\xa0\xa4\xc5\x99\xda\x2f\xb6\x24\x60"
136+			  "\xe2\x79\x4b\xaa\xb6\x6b\x85\x0b\xc9\xc6\x04\x66\x86"
137+			  "\xe2\xcc\xe2\x25\x3f\x4f\x09\xcd\xb8\x9d\xdb\xc1\x90"
138+			  "\xa9\x11\xbc\x35\x44\x69\x2d\x9c\x64\x4f\x13\x31\x64"
139+			  "\xcc\xfb\x4d\x95\x93\x86\x7f\x33\x7f\x1a\xef\xe9\x30"
140+			  "\xf9\x67\xa1\x94\x0a\x69\x0f\x60\xcd\xc3\xab\x99\xdc"
141+			  "\x42\xed\x97\x05\x00\x33\xc3\x15\x95\x3a\x06\xa0\x0e"
142+			  "\x20\xa9\x0e\x82\xb9\x43\x45\x01\xaa\x6d\xda\x0d",
143+		.output	= "zstd, short for Zstandard, is a fast lossless "
144+			  "compression algorithm, targeting real-time "
145+			  "compression scenarios at zlib-level and better "
146+			  "compression ratios. The zstd compression library "
147+			  "provides in-memory compression and decompression "
148+			  "functions.",
149+	},
150+};
151 #endif	/* _CRYPTO_TESTMGR_H */
152diff --git a/crypto/zstd.c b/crypto/zstd.c
153new file mode 100644
154index 0000000..9a76b3e
155--- /dev/null
156+++ b/crypto/zstd.c
157@@ -0,0 +1,265 @@
158+/*
159+ * Cryptographic API.
160+ *
161+ * Copyright (c) 2017-present, Facebook, Inc.
162+ *
163+ * This program is free software; you can redistribute it and/or modify it
164+ * under the terms of the GNU General Public License version 2 as published by
165+ * the Free Software Foundation.
166+ *
167+ * This program is distributed in the hope that it will be useful, but WITHOUT
168+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
169+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
170+ * more details.
171+ */
172+#include <linux/crypto.h>
173+#include <linux/init.h>
174+#include <linux/interrupt.h>
175+#include <linux/mm.h>
176+#include <linux/module.h>
177+#include <linux/net.h>
178+#include <linux/vmalloc.h>
179+#include <linux/zstd.h>
180+#include <crypto/internal/scompress.h>
181+
182+
183+#define ZSTD_DEF_LEVEL	3
184+
185+struct zstd_ctx {
186+	ZSTD_CCtx *cctx;
187+	ZSTD_DCtx *dctx;
188+	void *cwksp;
189+	void *dwksp;
190+};
191+
192+static ZSTD_parameters zstd_params(void)
193+{
194+	return ZSTD_getParams(ZSTD_DEF_LEVEL, 0, 0);
195+}
196+
197+static int zstd_comp_init(struct zstd_ctx *ctx)
198+{
199+	int ret = 0;
200+	const ZSTD_parameters params = zstd_params();
201+	const size_t wksp_size = ZSTD_CCtxWorkspaceBound(params.cParams);
202+
203+	ctx->cwksp = vzalloc(wksp_size);
204+	if (!ctx->cwksp) {
205+		ret = -ENOMEM;
206+		goto out;
207+	}
208+
209+	ctx->cctx = ZSTD_initCCtx(ctx->cwksp, wksp_size);
210+	if (!ctx->cctx) {
211+		ret = -EINVAL;
212+		goto out_free;
213+	}
214+out:
215+	return ret;
216+out_free:
217+	vfree(ctx->cwksp);
218+	goto out;
219+}
220+
221+static int zstd_decomp_init(struct zstd_ctx *ctx)
222+{
223+	int ret = 0;
224+	const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
225+
226+	ctx->dwksp = vzalloc(wksp_size);
227+	if (!ctx->dwksp) {
228+		ret = -ENOMEM;
229+		goto out;
230+	}
231+
232+	ctx->dctx = ZSTD_initDCtx(ctx->dwksp, wksp_size);
233+	if (!ctx->dctx) {
234+		ret = -EINVAL;
235+		goto out_free;
236+	}
237+out:
238+	return ret;
239+out_free:
240+	vfree(ctx->dwksp);
241+	goto out;
242+}
243+
244+static void zstd_comp_exit(struct zstd_ctx *ctx)
245+{
246+	vfree(ctx->cwksp);
247+	ctx->cwksp = NULL;
248+	ctx->cctx = NULL;
249+}
250+
251+static void zstd_decomp_exit(struct zstd_ctx *ctx)
252+{
253+	vfree(ctx->dwksp);
254+	ctx->dwksp = NULL;
255+	ctx->dctx = NULL;
256+}
257+
258+static int __zstd_init(void *ctx)
259+{
260+	int ret;
261+
262+	ret = zstd_comp_init(ctx);
263+	if (ret)
264+		return ret;
265+	ret = zstd_decomp_init(ctx);
266+	if (ret)
267+		zstd_comp_exit(ctx);
268+	return ret;
269+}
270+
271+static void *zstd_alloc_ctx(struct crypto_scomp *tfm)
272+{
273+	int ret;
274+	struct zstd_ctx *ctx;
275+
276+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
277+	if (!ctx)
278+		return ERR_PTR(-ENOMEM);
279+
280+	ret = __zstd_init(ctx);
281+	if (ret) {
282+		kfree(ctx);
283+		return ERR_PTR(ret);
284+	}
285+
286+	return ctx;
287+}
288+
289+static int zstd_init(struct crypto_tfm *tfm)
290+{
291+	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
292+
293+	return __zstd_init(ctx);
294+}
295+
296+static void __zstd_exit(void *ctx)
297+{
298+	zstd_comp_exit(ctx);
299+	zstd_decomp_exit(ctx);
300+}
301+
302+static void zstd_free_ctx(struct crypto_scomp *tfm, void *ctx)
303+{
304+	__zstd_exit(ctx);
305+	kzfree(ctx);
306+}
307+
308+static void zstd_exit(struct crypto_tfm *tfm)
309+{
310+	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
311+
312+	__zstd_exit(ctx);
313+}
314+
315+static int __zstd_compress(const u8 *src, unsigned int slen,
316+			   u8 *dst, unsigned int *dlen, void *ctx)
317+{
318+	size_t out_len;
319+	struct zstd_ctx *zctx = ctx;
320+	const ZSTD_parameters params = zstd_params();
321+
322+	out_len = ZSTD_compressCCtx(zctx->cctx, dst, *dlen, src, slen, params);
323+	if (ZSTD_isError(out_len))
324+		return -EINVAL;
325+	*dlen = out_len;
326+	return 0;
327+}
328+
329+static int zstd_compress(struct crypto_tfm *tfm, const u8 *src,
330+			 unsigned int slen, u8 *dst, unsigned int *dlen)
331+{
332+	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
333+
334+	return __zstd_compress(src, slen, dst, dlen, ctx);
335+}
336+
337+static int zstd_scompress(struct crypto_scomp *tfm, const u8 *src,
338+			  unsigned int slen, u8 *dst, unsigned int *dlen,
339+			  void *ctx)
340+{
341+	return __zstd_compress(src, slen, dst, dlen, ctx);
342+}
343+
344+static int __zstd_decompress(const u8 *src, unsigned int slen,
345+			     u8 *dst, unsigned int *dlen, void *ctx)
346+{
347+	size_t out_len;
348+	struct zstd_ctx *zctx = ctx;
349+
350+	out_len = ZSTD_decompressDCtx(zctx->dctx, dst, *dlen, src, slen);
351+	if (ZSTD_isError(out_len))
352+		return -EINVAL;
353+	*dlen = out_len;
354+	return 0;
355+}
356+
357+static int zstd_decompress(struct crypto_tfm *tfm, const u8 *src,
358+			   unsigned int slen, u8 *dst, unsigned int *dlen)
359+{
360+	struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
361+
362+	return __zstd_decompress(src, slen, dst, dlen, ctx);
363+}
364+
365+static int zstd_sdecompress(struct crypto_scomp *tfm, const u8 *src,
366+			    unsigned int slen, u8 *dst, unsigned int *dlen,
367+			    void *ctx)
368+{
369+	return __zstd_decompress(src, slen, dst, dlen, ctx);
370+}
371+
372+static struct crypto_alg alg = {
373+	.cra_name		= "zstd",
374+	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
375+	.cra_ctxsize		= sizeof(struct zstd_ctx),
376+	.cra_module		= THIS_MODULE,
377+	.cra_init		= zstd_init,
378+	.cra_exit		= zstd_exit,
379+	.cra_u			= { .compress = {
380+	.coa_compress		= zstd_compress,
381+	.coa_decompress		= zstd_decompress } }
382+};
383+
384+static struct scomp_alg scomp = {
385+	.alloc_ctx		= zstd_alloc_ctx,
386+	.free_ctx		= zstd_free_ctx,
387+	.compress		= zstd_scompress,
388+	.decompress		= zstd_sdecompress,
389+	.base			= {
390+		.cra_name	= "zstd",
391+		.cra_driver_name = "zstd-scomp",
392+		.cra_module	 = THIS_MODULE,
393+	}
394+};
395+
396+static int __init zstd_mod_init(void)
397+{
398+	int ret;
399+
400+	ret = crypto_register_alg(&alg);
401+	if (ret)
402+		return ret;
403+
404+	ret = crypto_register_scomp(&scomp);
405+	if (ret)
406+		crypto_unregister_alg(&alg);
407+
408+	return ret;
409+}
410+
411+static void __exit zstd_mod_fini(void)
412+{
413+	crypto_unregister_alg(&alg);
414+	crypto_unregister_scomp(&scomp);
415+}
416+
417+module_init(zstd_mod_init);
418+module_exit(zstd_mod_fini);
419+
420+MODULE_LICENSE("GPL");
421+MODULE_DESCRIPTION("Zstd Compression Algorithm");
422+MODULE_ALIAS_CRYPTO("zstd");
423--
4242.9.3
425