2022-03-04 14:18:24

by Meenakshi Aggarwal

[permalink] [raw]
Subject: [PATCH] crypto: caam/rng: Add support for PRNG

From: Meenakshi Aggarwal <[email protected]>

Add support for random number generation using PRNG
mode of CAAM and expose the interface through crypto API.

Signed-off-by: Meenakshi Aggarwal <[email protected]>
---
drivers/crypto/caam/Kconfig | 9 ++
drivers/crypto/caam/Makefile | 1 +
drivers/crypto/caam/caamprng.c | 238 +++++++++++++++++++++++++++++++++
drivers/crypto/caam/desc.h | 1 +
drivers/crypto/caam/intern.h | 15 +++
drivers/crypto/caam/jr.c | 2 +
6 files changed, 266 insertions(+)
create mode 100644 drivers/crypto/caam/caamprng.c

diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index 84ea7cba5ee5..d94250348b32 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -151,6 +151,15 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
Selecting this will register the SEC4 hardware rng to
the hw_random API for supplying the kernel entropy pool.

+
+config CRYPTO_DEV_FSL_CAAM_PRNG_API
+ bool "Register Pseudo random number generation implementation with Crypto API"
+ default y
+ select CRYPTO_RNG
+ help
+ Selecting this will register the SEC hardware prng to
+ the Crypto API.
+
endif # CRYPTO_DEV_FSL_CAAM_JR

endif # CRYPTO_DEV_FSL_CAAM
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
index 3570286eb9ce..59961a0bbfe4 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -21,6 +21,7 @@ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API) += caamprng.o

caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
diff --git a/drivers/crypto/caam/caamprng.c b/drivers/crypto/caam/caamprng.c
new file mode 100644
index 000000000000..be0cf0e214f0
--- /dev/null
+++ b/drivers/crypto/caam/caamprng.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver to expose SEC4 PRNG via crypto RNG API
+ *
+ * Copyright 2022 NXP
+ *
+ */
+
+#include <linux/completion.h>
+#include <crypto/internal/rng.h>
+#include "compat.h"
+#include "regs.h"
+#include "intern.h"
+#include "desc_constr.h"
+#include "jr.h"
+#include "error.h"
+
+/*
+ * Length of used descriptors, see caam_init_desc()
+ */
+#define CAAM_PRNG_DESC_LEN (CAAM_CMD_SZ + \
+ CAAM_CMD_SZ + \
+ CAAM_CMD_SZ + CAAM_PTR_SZ_MAX)
+
+/* prng per-device context */
+struct caam_prng_ctx {
+ struct device *jrdev;
+ struct completion done;
+};
+
+struct caam_prng_alg {
+ struct rng_alg rng;
+ bool registered;
+};
+
+static void caam_prng_done(struct device *jrdev, u32 *desc, u32 err,
+ void *context)
+{
+ struct caam_prng_ctx *jctx = context;
+
+ if (err)
+ caam_jr_strstatus(jrdev, err);
+
+ complete(&jctx->done);
+}
+
+static u32 *caam_init_reseed_desc(u32 *desc, dma_addr_t seed_dma, u32 len)
+{
+ init_job_desc(desc, 0); /* + 1 cmd_sz */
+ /* Generate random bytes: + 1 cmd_sz */
+ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
+ OP_ALG_AS_FINALIZE | OP_ALG_AI_ON);
+ /* Store bytes: + 1 cmd_sz + caam_ptr_sz */
+ append_load(desc, seed_dma, len, CLASS_1 | LDST_SRCDST_BYTE_CONTEXT);
+
+ print_hex_dump_debug("prng reseed desc@: ", DUMP_PREFIX_ADDRESS,
+ 16, 4, desc, desc_bytes(desc), 1);
+
+ return desc;
+}
+
+static u32 *caam_init_prng_desc(u32 *desc, dma_addr_t dst_dma, u32 len)
+{
+ init_job_desc(desc, 0); /* + 1 cmd_sz */
+ /* Generate random bytes: + 1 cmd_sz */
+ append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG);
+ /* Store bytes: + 1 cmd_sz + caam_ptr_sz */
+ append_fifo_store(desc, dst_dma,
+ len, FIFOST_TYPE_RNGSTORE);
+
+ print_hex_dump_debug("prng job desc@: ", DUMP_PREFIX_ADDRESS,
+ 16, 4, desc, desc_bytes(desc), 1);
+
+ return desc;
+}
+
+static int caam_prng_generate(struct crypto_rng *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int dlen)
+{
+ struct caam_prng_ctx ctx;
+ dma_addr_t dst_dma;
+ u32 *desc;
+ int ret;
+
+ ctx.jrdev = caam_jr_alloc();
+ ret = PTR_ERR_OR_ZERO(ctx.jrdev);
+ if (ret) {
+ pr_err("Job Ring Device allocation failed\n");
+ return ret;
+ }
+
+ desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA);
+ if (!desc) {
+ caam_jr_free(ctx.jrdev);
+ return -ENOMEM;
+ }
+
+ dst_dma = dma_map_single(ctx.jrdev, dst, dlen, DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx.jrdev, dst_dma)) {
+ dev_err(ctx.jrdev, "Failed to map destination buffer memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ init_completion(&ctx.done);
+ ret = caam_jr_enqueue(ctx.jrdev,
+ caam_init_prng_desc(desc, dst_dma, dlen),
+ caam_prng_done, &ctx);
+
+ if (ret == -EINPROGRESS) {
+ wait_for_completion(&ctx.done);
+ ret = 0;
+ }
+
+ dma_unmap_single(ctx.jrdev, dst_dma, dlen, DMA_FROM_DEVICE);
+
+out:
+ kfree(desc);
+ caam_jr_free(ctx.jrdev);
+ return ret;
+}
+
+static void caam_prng_exit(struct crypto_tfm *tfm)
+{
+
+ return;
+}
+
+static int caam_prng_init(struct crypto_tfm *tfm)
+{
+ return 0;
+}
+
+static int caam_prng_seed(struct crypto_rng *tfm,
+ const u8 *seed, unsigned int slen)
+{
+ struct caam_prng_ctx ctx;
+ dma_addr_t seed_dma;
+ u32 *desc;
+ int ret;
+
+ ctx.jrdev = caam_jr_alloc();
+ ret = PTR_ERR_OR_ZERO(ctx.jrdev);
+ if (ret) {
+ pr_err("Job Ring Device allocation failed\n");
+ return ret;
+ }
+
+ desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA);
+ if (!desc) {
+ caam_jr_free(ctx.jrdev);
+ return -ENOMEM;
+ }
+
+ seed_dma = dma_map_single(ctx.jrdev, seed, slen, DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx.jrdev, seed_dma)) {
+ dev_err(ctx.jrdev, "Failed to map destination buffer memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ init_completion(&ctx.done);
+ ret = caam_jr_enqueue(ctx.jrdev,
+ caam_init_reseed_desc(desc, seed_dma, slen),
+ caam_prng_done, &ctx);
+
+ if (ret == -EINPROGRESS) {
+ wait_for_completion(&ctx.done);
+ ret = 0;
+ }
+
+ dma_unmap_single(ctx.jrdev, seed_dma, slen, DMA_FROM_DEVICE);
+
+out:
+ kfree(desc);
+ caam_jr_free(ctx.jrdev);
+ return ret;
+}
+
+static struct caam_prng_alg caam_prng_alg = {
+ .rng = {
+ .generate = caam_prng_generate,
+ .seed = caam_prng_seed,
+ .seedsize = 32,
+ .base = {
+ .cra_name = "stdrng",
+ .cra_driver_name = "prng-caam",
+ .cra_priority = 500,
+ .cra_ctxsize = sizeof(struct caam_prng_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_init = caam_prng_init,
+ .cra_exit = caam_prng_exit,
+ },
+ }
+};
+
+void caam_prng_unregister(void *data)
+{
+ if (caam_prng_alg.registered)
+ crypto_unregister_rng(&caam_prng_alg.rng);
+}
+
+int caam_prng_register(struct device *ctrldev)
+{
+ struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
+ u32 rng_inst;
+ int ret = 0;
+
+ /* Check for available RNG blocks before registration */
+ if (priv->era < 10)
+ rng_inst = (rd_reg32(&priv->jr[0]->perfmon.cha_num_ls) &
+ CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
+ else
+ rng_inst = rd_reg32(&priv->jr[0]->vreg.rng) & CHA_VER_NUM_MASK;
+
+ if (!rng_inst) {
+ dev_dbg(ctrldev, "RNG block is not available..."
+ "skipping registering rng algorithm\n");
+
+ return ret;
+ }
+
+ ret = crypto_register_rng(&caam_prng_alg.rng);
+ if (ret) {
+ dev_err(ctrldev,
+ "couldn't register rng crypto alg: %d\n",
+ ret);
+ return ret;
+ }
+
+ caam_prng_alg.registered = true;
+
+ dev_info(ctrldev,
+ "rng crypto API alg registered %s\n", caam_prng_alg.rng.base.cra_name);
+
+ return 0;
+}
diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h
index e13470901586..33db8ed2b49e 100644
--- a/drivers/crypto/caam/desc.h
+++ b/drivers/crypto/caam/desc.h
@@ -1255,6 +1255,7 @@
#define OP_ALG_ICV_ON (1 << OP_ALG_ICV_SHIFT)

#define OP_ALG_PR_ON BIT(1)
+#define OP_ALG_AI_ON BIT(11)

#define OP_ALG_DIR_SHIFT 0
#define OP_ALG_DIR_MASK 1
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index 7d45b21bd55a..c2f51365df1b 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -185,6 +185,21 @@ static inline void caam_rng_exit(struct device *dev) {}

#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API */

+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API
+
+int caam_prng_register(struct device *dev);
+void caam_prng_unregister(void *data);
+
+#else
+
+static inline int caam_prng_register(struct device *dev)
+{
+ return 0;
+}
+
+static inline void caam_prng_unregister(void *data) {}
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API */
+
#ifdef CONFIG_CAAM_QI

int caam_qi_algapi_init(struct device *dev);
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 7f2b1101f567..11849362f912 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -39,6 +39,7 @@ static void register_algs(struct caam_drv_private_jr *jrpriv,
caam_algapi_hash_init(dev);
caam_pkc_init(dev);
jrpriv->hwrng = !caam_rng_init(dev);
+ caam_prng_register(dev);
caam_qi_algapi_init(dev);

algs_unlock:
@@ -56,6 +57,7 @@ static void unregister_algs(void)

caam_pkc_exit();
caam_algapi_hash_exit();
+ caam_prng_unregister(NULL);
caam_algapi_exit();

algs_unlock:
--
2.25.1


2022-03-08 23:41:54

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] crypto: caam/rng: Add support for PRNG

Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on herbert-cryptodev-2.6/master]
[also build test WARNING on herbert-crypto-2.6/master v5.17-rc7 next-20220308]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/meenakshi-aggarwal-nxp-com/crypto-caam-rng-Add-support-for-PRNG/20220307-142401
base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: arm-multi_v7_defconfig (https://download.01.org/0day-ci/archive/20220309/[email protected]/config)
compiler: arm-linux-gnueabi-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/bc27c1a2748de5052fb4c042d90fa1e0e4132043
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review meenakshi-aggarwal-nxp-com/crypto-caam-rng-Add-support-for-PRNG/20220307-142401
git checkout bc27c1a2748de5052fb4c042d90fa1e0e4132043
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arm SHELL=/bin/bash drivers/crypto/caam/ drivers/rtc/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

In file included from drivers/crypto/caam/compat.h:18,
from drivers/crypto/caam/caamprng.c:11:
drivers/crypto/caam/caamprng.c: In function 'caam_prng_seed':
>> drivers/crypto/caam/caamprng.c:156:46: warning: passing argument 2 of 'dma_map_single_attrs' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
156 | seed_dma = dma_map_single(ctx.jrdev, seed, slen, DMA_FROM_DEVICE);
| ^~~~
include/linux/dma-mapping.h:406:60: note: in definition of macro 'dma_map_single'
406 | #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
| ^
include/linux/dma-mapping.h:322:73: note: expected 'void *' but argument is of type 'const u8 *' {aka 'const unsigned char *'}
322 | static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
| ~~~~~~^~~


vim +156 drivers/crypto/caam/caamprng.c

> 11 #include "compat.h"
12 #include "regs.h"
13 #include "intern.h"
14 #include "desc_constr.h"
15 #include "jr.h"
16 #include "error.h"
17
18 /*
19 * Length of used descriptors, see caam_init_desc()
20 */
21 #define CAAM_PRNG_DESC_LEN (CAAM_CMD_SZ + \
22 CAAM_CMD_SZ + \
23 CAAM_CMD_SZ + CAAM_PTR_SZ_MAX)
24
25 /* prng per-device context */
26 struct caam_prng_ctx {
27 struct device *jrdev;
28 struct completion done;
29 };
30
31 struct caam_prng_alg {
32 struct rng_alg rng;
33 bool registered;
34 };
35
36 static void caam_prng_done(struct device *jrdev, u32 *desc, u32 err,
37 void *context)
38 {
39 struct caam_prng_ctx *jctx = context;
40
41 if (err)
42 caam_jr_strstatus(jrdev, err);
43
44 complete(&jctx->done);
45 }
46
47 static u32 *caam_init_reseed_desc(u32 *desc, dma_addr_t seed_dma, u32 len)
48 {
49 init_job_desc(desc, 0); /* + 1 cmd_sz */
50 /* Generate random bytes: + 1 cmd_sz */
51 append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
52 OP_ALG_AS_FINALIZE | OP_ALG_AI_ON);
53 /* Store bytes: + 1 cmd_sz + caam_ptr_sz */
54 append_load(desc, seed_dma, len, CLASS_1 | LDST_SRCDST_BYTE_CONTEXT);
55
56 print_hex_dump_debug("prng reseed desc@: ", DUMP_PREFIX_ADDRESS,
57 16, 4, desc, desc_bytes(desc), 1);
58
59 return desc;
60 }
61
62 static u32 *caam_init_prng_desc(u32 *desc, dma_addr_t dst_dma, u32 len)
63 {
64 init_job_desc(desc, 0); /* + 1 cmd_sz */
65 /* Generate random bytes: + 1 cmd_sz */
66 append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG);
67 /* Store bytes: + 1 cmd_sz + caam_ptr_sz */
68 append_fifo_store(desc, dst_dma,
69 len, FIFOST_TYPE_RNGSTORE);
70
71 print_hex_dump_debug("prng job desc@: ", DUMP_PREFIX_ADDRESS,
72 16, 4, desc, desc_bytes(desc), 1);
73
74 return desc;
75 }
76
77 static int caam_prng_generate(struct crypto_rng *tfm,
78 const u8 *src, unsigned int slen,
79 u8 *dst, unsigned int dlen)
80 {
81 struct caam_prng_ctx ctx;
82 dma_addr_t dst_dma;
83 u32 *desc;
84 int ret;
85
86 ctx.jrdev = caam_jr_alloc();
87 ret = PTR_ERR_OR_ZERO(ctx.jrdev);
88 if (ret) {
89 pr_err("Job Ring Device allocation failed\n");
90 return ret;
91 }
92
93 desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA);
94 if (!desc) {
95 caam_jr_free(ctx.jrdev);
96 return -ENOMEM;
97 }
98
99 dst_dma = dma_map_single(ctx.jrdev, dst, dlen, DMA_FROM_DEVICE);
100 if (dma_mapping_error(ctx.jrdev, dst_dma)) {
101 dev_err(ctx.jrdev, "Failed to map destination buffer memory\n");
102 ret = -ENOMEM;
103 goto out;
104 }
105
106 init_completion(&ctx.done);
107 ret = caam_jr_enqueue(ctx.jrdev,
108 caam_init_prng_desc(desc, dst_dma, dlen),
109 caam_prng_done, &ctx);
110
111 if (ret == -EINPROGRESS) {
112 wait_for_completion(&ctx.done);
113 ret = 0;
114 }
115
116 dma_unmap_single(ctx.jrdev, dst_dma, dlen, DMA_FROM_DEVICE);
117
118 out:
119 kfree(desc);
120 caam_jr_free(ctx.jrdev);
121 return ret;
122 }
123
124 static void caam_prng_exit(struct crypto_tfm *tfm)
125 {
126
127 return;
128 }
129
130 static int caam_prng_init(struct crypto_tfm *tfm)
131 {
132 return 0;
133 }
134
135 static int caam_prng_seed(struct crypto_rng *tfm,
136 const u8 *seed, unsigned int slen)
137 {
138 struct caam_prng_ctx ctx;
139 dma_addr_t seed_dma;
140 u32 *desc;
141 int ret;
142
143 ctx.jrdev = caam_jr_alloc();
144 ret = PTR_ERR_OR_ZERO(ctx.jrdev);
145 if (ret) {
146 pr_err("Job Ring Device allocation failed\n");
147 return ret;
148 }
149
150 desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA);
151 if (!desc) {
152 caam_jr_free(ctx.jrdev);
153 return -ENOMEM;
154 }
155
> 156 seed_dma = dma_map_single(ctx.jrdev, seed, slen, DMA_FROM_DEVICE);
157 if (dma_mapping_error(ctx.jrdev, seed_dma)) {
158 dev_err(ctx.jrdev, "Failed to map destination buffer memory\n");
159 ret = -ENOMEM;
160 goto out;
161 }
162
163 init_completion(&ctx.done);
164 ret = caam_jr_enqueue(ctx.jrdev,
165 caam_init_reseed_desc(desc, seed_dma, slen),
166 caam_prng_done, &ctx);
167
168 if (ret == -EINPROGRESS) {
169 wait_for_completion(&ctx.done);
170 ret = 0;
171 }
172
173 dma_unmap_single(ctx.jrdev, seed_dma, slen, DMA_FROM_DEVICE);
174
175 out:
176 kfree(desc);
177 caam_jr_free(ctx.jrdev);
178 return ret;
179 }
180

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]

2022-03-17 05:35:39

by Meenakshi Aggarwal

[permalink] [raw]
Subject: [PATCH v2 0/1] crypto: caam/rng: Add support for PRNG

From: Meenakshi Aggarwal <[email protected]>

changes in v2:
- rebase to latest master
- fixed compile time warning reported by kernel test robot
- fixed checkpatch warning
- fixed "rejecting DMA map of vmalloc memory" issue while running
"ecdh-nist-p256" algorithm self-test. This test uses caam prng's
to generate random number for its key.

Meenakshi Aggarwal (1):
crypto: caam/rng: Add support for PRNG

drivers/crypto/caam/Kconfig | 9 ++
drivers/crypto/caam/Makefile | 1 +
drivers/crypto/caam/caamprng.c | 256 +++++++++++++++++++++++++++++++++
drivers/crypto/caam/desc.h | 1 +
drivers/crypto/caam/intern.h | 15 ++
drivers/crypto/caam/jr.c | 2 +
6 files changed, 284 insertions(+)
create mode 100644 drivers/crypto/caam/caamprng.c


base-commit: 56e337f2cf1326323844927a04e9dbce9a244835
--
2.25.1

2022-04-20 07:22:47

by Meenakshi Aggarwal

[permalink] [raw]
Subject: [PATCH v3 0/1] crypto: caam/rng: Add support for PRNG

From: Meenakshi Aggarwal <[email protected]>

changes in v3:
- rebase to latest master
- incorporated review comments

Meenakshi Aggarwal (1):
crypto: caam/rng: Add support for PRNG

drivers/crypto/caam/Kconfig | 9 ++
drivers/crypto/caam/Makefile | 1 +
drivers/crypto/caam/caamprng.c | 260 +++++++++++++++++++++++++++++++++
drivers/crypto/caam/desc.h | 1 +
drivers/crypto/caam/intern.h | 15 ++
drivers/crypto/caam/jr.c | 3 +-
6 files changed, 288 insertions(+), 1 deletion(-)
create mode 100644 drivers/crypto/caam/caamprng.c


base-commit: 559089e0a93d44280ec3ab478830af319c56dbe3
--
2.25.1