1 // SPDX-License-Identifier: GPL-2.0
3 * OpenSSL/Cryptogams accelerated Poly1305 transform for MIPS
5 * Copyright (C) 2019 Linaro Ltd. <ard.biesheuvel@linaro.org>
8 #include <asm/unaligned.h>
9 #include <crypto/algapi.h>
10 #include <crypto/internal/hash.h>
11 #include <crypto/internal/poly1305.h>
12 #include <linux/cpufeature.h>
13 #include <linux/crypto.h>
14 #include <linux/module.h>
16 asmlinkage
void poly1305_init_mips(void *state
, const u8
*key
);
17 asmlinkage
void poly1305_blocks_mips(void *state
, const u8
*src
, u32 len
, u32 hibit
);
18 asmlinkage
void poly1305_emit_mips(void *state
, u8
*digest
, const u32
*nonce
);
20 void poly1305_init_arch(struct poly1305_desc_ctx
*dctx
, const u8
*key
)
22 poly1305_init_mips(&dctx
->h
, key
);
23 dctx
->s
[0] = get_unaligned_le32(key
+ 16);
24 dctx
->s
[1] = get_unaligned_le32(key
+ 20);
25 dctx
->s
[2] = get_unaligned_le32(key
+ 24);
26 dctx
->s
[3] = get_unaligned_le32(key
+ 28);
29 EXPORT_SYMBOL(poly1305_init_arch
);
31 static int mips_poly1305_init(struct shash_desc
*desc
)
33 struct poly1305_desc_ctx
*dctx
= shash_desc_ctx(desc
);
42 static void mips_poly1305_blocks(struct poly1305_desc_ctx
*dctx
, const u8
*src
,
45 if (unlikely(!dctx
->sset
)) {
47 poly1305_init_mips(&dctx
->h
, src
);
48 src
+= POLY1305_BLOCK_SIZE
;
49 len
-= POLY1305_BLOCK_SIZE
;
52 if (len
>= POLY1305_BLOCK_SIZE
) {
53 dctx
->s
[0] = get_unaligned_le32(src
+ 0);
54 dctx
->s
[1] = get_unaligned_le32(src
+ 4);
55 dctx
->s
[2] = get_unaligned_le32(src
+ 8);
56 dctx
->s
[3] = get_unaligned_le32(src
+ 12);
57 src
+= POLY1305_BLOCK_SIZE
;
58 len
-= POLY1305_BLOCK_SIZE
;
61 if (len
< POLY1305_BLOCK_SIZE
)
65 len
&= ~(POLY1305_BLOCK_SIZE
- 1);
67 poly1305_blocks_mips(&dctx
->h
, src
, len
, hibit
);
70 static int mips_poly1305_update(struct shash_desc
*desc
, const u8
*src
,
73 struct poly1305_desc_ctx
*dctx
= shash_desc_ctx(desc
);
75 if (unlikely(dctx
->buflen
)) {
76 u32 bytes
= min(len
, POLY1305_BLOCK_SIZE
- dctx
->buflen
);
78 memcpy(dctx
->buf
+ dctx
->buflen
, src
, bytes
);
81 dctx
->buflen
+= bytes
;
83 if (dctx
->buflen
== POLY1305_BLOCK_SIZE
) {
84 mips_poly1305_blocks(dctx
, dctx
->buf
, POLY1305_BLOCK_SIZE
, 1);
89 if (likely(len
>= POLY1305_BLOCK_SIZE
)) {
90 mips_poly1305_blocks(dctx
, src
, len
, 1);
91 src
+= round_down(len
, POLY1305_BLOCK_SIZE
);
92 len
%= POLY1305_BLOCK_SIZE
;
97 memcpy(dctx
->buf
, src
, len
);
102 void poly1305_update_arch(struct poly1305_desc_ctx
*dctx
, const u8
*src
,
105 if (unlikely(dctx
->buflen
)) {
106 u32 bytes
= min(nbytes
, POLY1305_BLOCK_SIZE
- dctx
->buflen
);
108 memcpy(dctx
->buf
+ dctx
->buflen
, src
, bytes
);
111 dctx
->buflen
+= bytes
;
113 if (dctx
->buflen
== POLY1305_BLOCK_SIZE
) {
114 poly1305_blocks_mips(&dctx
->h
, dctx
->buf
,
115 POLY1305_BLOCK_SIZE
, 1);
120 if (likely(nbytes
>= POLY1305_BLOCK_SIZE
)) {
121 unsigned int len
= round_down(nbytes
, POLY1305_BLOCK_SIZE
);
123 poly1305_blocks_mips(&dctx
->h
, src
, len
, 1);
125 nbytes
%= POLY1305_BLOCK_SIZE
;
128 if (unlikely(nbytes
)) {
129 dctx
->buflen
= nbytes
;
130 memcpy(dctx
->buf
, src
, nbytes
);
133 EXPORT_SYMBOL(poly1305_update_arch
);
135 void poly1305_final_arch(struct poly1305_desc_ctx
*dctx
, u8
*dst
)
137 if (unlikely(dctx
->buflen
)) {
138 dctx
->buf
[dctx
->buflen
++] = 1;
139 memset(dctx
->buf
+ dctx
->buflen
, 0,
140 POLY1305_BLOCK_SIZE
- dctx
->buflen
);
141 poly1305_blocks_mips(&dctx
->h
, dctx
->buf
, POLY1305_BLOCK_SIZE
, 0);
144 poly1305_emit_mips(&dctx
->h
, dst
, dctx
->s
);
145 *dctx
= (struct poly1305_desc_ctx
){};
147 EXPORT_SYMBOL(poly1305_final_arch
);
149 static int mips_poly1305_final(struct shash_desc
*desc
, u8
*dst
)
151 struct poly1305_desc_ctx
*dctx
= shash_desc_ctx(desc
);
153 if (unlikely(!dctx
->sset
))
156 poly1305_final_arch(dctx
, dst
);
160 static struct shash_alg mips_poly1305_alg
= {
161 .init
= mips_poly1305_init
,
162 .update
= mips_poly1305_update
,
163 .final
= mips_poly1305_final
,
164 .digestsize
= POLY1305_DIGEST_SIZE
,
165 .descsize
= sizeof(struct poly1305_desc_ctx
),
167 .base
.cra_name
= "poly1305",
168 .base
.cra_driver_name
= "poly1305-mips",
169 .base
.cra_priority
= 200,
170 .base
.cra_blocksize
= POLY1305_BLOCK_SIZE
,
171 .base
.cra_module
= THIS_MODULE
,
174 static int __init
mips_poly1305_mod_init(void)
176 return IS_REACHABLE(CONFIG_CRYPTO_HASH
) ?
177 crypto_register_shash(&mips_poly1305_alg
) : 0;
180 static void __exit
mips_poly1305_mod_exit(void)
182 if (IS_REACHABLE(CONFIG_CRYPTO_HASH
))
183 crypto_unregister_shash(&mips_poly1305_alg
);
186 module_init(mips_poly1305_mod_init
);
187 module_exit(mips_poly1305_mod_exit
);
189 MODULE_LICENSE("GPL v2");
190 MODULE_ALIAS_CRYPTO("poly1305");
191 MODULE_ALIAS_CRYPTO("poly1305-mips");