[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251215-ascon_hash256-v1-2-24ae735e571e@kriptograf.id>
Date: Mon, 15 Dec 2025 14:54:35 +0700
From: "Rusydi H. Makarim" <rusydi.makarim@...ptograf.id>
To: Herbert Xu <herbert@...dor.apana.org.au>,
"David S. Miller" <davem@...emloft.net>, Eric Biggers <ebiggers@...nel.org>,
"Jason A. Donenfeld" <Jason@...c4.com>, Ard Biesheuvel <ardb@...nel.org>
Cc: linux-kernel@...r.kernel.org, linux-crypto@...r.kernel.org,
"Rusydi H. Makarim" <rusydi.makarim@...ptograf.id>
Subject: [PATCH 2/3] lib/crypto: Initial implementation of Ascon-Hash256
initial implementation of Ascon-Hash256
Signed-off-by: Rusydi H. Makarim <rusydi.makarim@...ptograf.id>
---
include/crypto/ascon_hash.h | 2 +-
lib/crypto/Kconfig | 8 +++
lib/crypto/Makefile | 5 ++
lib/crypto/ascon_hash.c | 154 ++++++++++++++++++++++++++++++++++++++++++++
lib/crypto/hash_info.c | 2 +
5 files changed, 170 insertions(+), 1 deletion(-)
diff --git a/include/crypto/ascon_hash.h b/include/crypto/ascon_hash.h
index bb3561a745a9..c03a1414eec9 100644
--- a/include/crypto/ascon_hash.h
+++ b/include/crypto/ascon_hash.h
@@ -18,7 +18,7 @@
/*
* The standard of Ascon permutation in NIST SP 800-232 specifies 16 round
- * constants to accomodate potential functionality extensions in the future
+ * constants to accommodate potential functionality extensions in the future
* (see page 2).
*/
static const u64 ascon_p_rndc[] = {
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index 6871a41e5069..5f39ed6746de 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -223,6 +223,14 @@ config CRYPTO_LIB_SHA3_ARCH
default y if ARM64 && KERNEL_MODE_NEON
default y if S390
+config CRYPTO_LIB_ASCON_HASH
+ tristate
+ select CRYPTO_LIB_UTILS
+ help
+ The Ascon-Hash library functions. Select this if your module uses any of
+ the functions from <crypto/ascon_hash.h>
+
+
config CRYPTO_LIB_SM3
tristate
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index 330ab65b29c4..6657ea3d8771 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -297,6 +297,11 @@ endif # CONFIG_CRYPTO_LIB_SHA3_ARCH
################################################################################
+obj-$(CONFIG_CRYPTO_LIB_ASCON_HASH) += libascon_hash.o
+libascon_hash-y := ascon_hash.o
+
+################################################################################
+
obj-$(CONFIG_MPILIB) += mpi/
obj-$(CONFIG_CRYPTO_SELFTESTS_FULL) += simd.o
diff --git a/lib/crypto/ascon_hash.c b/lib/crypto/ascon_hash.c
new file mode 100644
index 000000000000..e435a0e72195
--- /dev/null
+++ b/lib/crypto/ascon_hash.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Ascon-Hash library functions
+ *
+ * Copyright (c) 2025 Rusydi H. Makarim <rusydi.makarim@...ptograf.id>
+ */
+
+#include <linux/module.h>
+#include <crypto/ascon_hash.h>
+#include <crypto/utils.h>
+
+
+static inline void ascon_round(u64 s[ASCON_STATE_WORDS], u64 C)
+{
+ u64 t[ASCON_STATE_WORDS];
+
+ // pC
+ s[2] ^= C;
+
+ // pS
+ s[0] ^= s[4];
+ s[4] ^= s[3];
+ s[2] ^= s[1];
+ t[0] = s[0] ^ (~s[1] & s[2]);
+ t[1] = s[1] ^ (~s[2] & s[3]);
+ t[2] = s[2] ^ (~s[3] & s[4]);
+ t[3] = s[3] ^ (~s[4] & s[0]);
+ t[4] = s[4] ^ (~s[0] & s[1]);
+ t[1] ^= t[0];
+ t[0] ^= t[4];
+ t[3] ^= t[2];
+ t[2] = ~t[2];
+
+ // pL
+ s[0] = t[0] ^ ror64(t[0], 19) ^ ror64(t[0], 28);
+ s[1] = t[1] ^ ror64(t[1], 61) ^ ror64(t[1], 39);
+ s[2] = t[2] ^ ror64(t[2], 1) ^ ror64(t[2], 6);
+ s[3] = t[3] ^ ror64(t[3], 10) ^ ror64(t[3], 17);
+ s[4] = t[4] ^ ror64(t[4], 7) ^ ror64(t[4], 41);
+}
+
+static inline void ascon_p12_generic(struct ascon_state *state)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(state->words); ++i)
+ state->native_words[i] = le64_to_cpu(state->words[i]);
+
+ for (i = 0; i < 12; ++i)
+ ascon_round(state->native_words, ascon_p_rndc[16 - 12 + i]);
+
+ for (i = 0; i < ARRAY_SIZE(state->words); ++i)
+ state->words[i] = cpu_to_le64(state->native_words[i]);
+}
+
+static void __maybe_unused ascon_hash256_absorb_blocks_generic(
+ struct ascon_state *state, const u8 *in, size_t nblocks)
+{
+ do {
+ for (size_t i = 0; i < ASCON_HASH256_BLOCK_SIZE; i += 8)
+ state->words[i / 8] ^= get_unaligned((__le64 *)&in[i]);
+ ascon_p12_generic(state);
+ in += ASCON_HASH256_BLOCK_SIZE;
+ } while (--nblocks);
+}
+
+#define ascon_p12 ascon_p12_generic
+#define ascon_hash256_absorb_blocks ascon_hash256_absorb_blocks_generic
+
+void ascon_hash256_init(struct ascon_hash256_ctx *asc_hash256_ctx)
+{
+ struct __ascon_hash_ctx *ctx = &asc_hash256_ctx->ctx;
+
+ ctx->state.words[0] = ASCON_HASH256_IV;
+ ctx->state.words[1] = 0;
+ ctx->state.words[2] = 0;
+ ctx->state.words[3] = 0;
+ ctx->state.words[4] = 0;
+ ctx->absorb_offset = 0;
+ ascon_p12(&ctx->state);
+}
+EXPORT_SYMBOL_GPL(ascon_hash256_init);
+
+void ascon_hash256_update(struct ascon_hash256_ctx *asc_hash256_ctx, const u8 *in,
+ size_t in_len)
+{
+ struct __ascon_hash_ctx *ctx = &asc_hash256_ctx->ctx;
+ u8 absorb_offset = ctx->absorb_offset;
+
+ WARN_ON_ONCE(absorb_offset >= ASCON_HASH256_BLOCK_SIZE);
+
+ if (absorb_offset && absorb_offset + in_len >= ASCON_HASH256_BLOCK_SIZE) {
+ crypto_xor(&ctx->state.bytes[absorb_offset], in,
+ ASCON_HASH256_BLOCK_SIZE - absorb_offset);
+ in += ASCON_HASH256_BLOCK_SIZE - absorb_offset;
+ in_len -= ASCON_HASH256_BLOCK_SIZE - absorb_offset;
+ ascon_p12(&ctx->state);
+ absorb_offset = 0;
+ }
+
+ if (in_len >= ASCON_HASH256_BLOCK_SIZE) {
+ size_t nblocks = in_len / ASCON_HASH256_BLOCK_SIZE;
+
+ ascon_hash256_absorb_blocks(&ctx->state, in, nblocks);
+ in += nblocks * ASCON_HASH256_BLOCK_SIZE;
+ in_len -= nblocks * ASCON_HASH256_BLOCK_SIZE;
+ }
+
+ if (in_len) {
+ crypto_xor(&ctx->state.bytes[absorb_offset], in, in_len);
+ absorb_offset += in_len;
+
+ }
+ ctx->absorb_offset = absorb_offset;
+}
+EXPORT_SYMBOL_GPL(ascon_hash256_update);
+
+void ascon_hash256_final(struct ascon_hash256_ctx *asc_hash256_ctx,
+ u8 out[ASCON_HASH256_DIGEST_SIZE])
+{
+ struct __ascon_hash_ctx *ctx = &asc_hash256_ctx->ctx;
+
+ // padding
+ ctx->state.bytes[ctx->absorb_offset] ^= 0x01;
+ ascon_p12(&ctx->state);
+
+ // squeezing
+ size_t len = ASCON_HASH256_DIGEST_SIZE;
+
+ while (len > ASCON_HASH256_RATE) {
+ memcpy(out, ctx->state.bytes, ASCON_HASH256_RATE);
+ ascon_p12(&ctx->state);
+ out += ASCON_HASH256_RATE;
+ len -= ASCON_HASH256_RATE;
+ }
+ memcpy(out, ctx->state.bytes, ASCON_HASH256_RATE);
+ memzero_explicit(asc_hash256_ctx, sizeof(*asc_hash256_ctx));
+}
+EXPORT_SYMBOL_GPL(ascon_hash256_final);
+
+
+void ascon_hash256(const u8 *in, size_t in_len,
+ u8 out[ASCON_HASH256_DIGEST_SIZE])
+{
+ struct ascon_hash256_ctx ctx;
+
+ ascon_hash256_init(&ctx);
+ ascon_hash256_update(&ctx, in, in_len);
+ ascon_hash256_final(&ctx, out);
+}
+EXPORT_SYMBOL_GPL(ascon_hash256);
+
+MODULE_DESCRIPTION("Ascon-Hash256 library functions");
+MODULE_LICENSE("GPL");
diff --git a/lib/crypto/hash_info.c b/lib/crypto/hash_info.c
index 9a467638c971..49ce182c6d08 100644
--- a/lib/crypto/hash_info.c
+++ b/lib/crypto/hash_info.c
@@ -32,6 +32,7 @@ const char *const hash_algo_name[HASH_ALGO__LAST] = {
[HASH_ALGO_SHA3_256] = "sha3-256",
[HASH_ALGO_SHA3_384] = "sha3-384",
[HASH_ALGO_SHA3_512] = "sha3-512",
+ [HASH_ALGO_ASCON_HASH256] = "ascon-hash256",
};
EXPORT_SYMBOL_GPL(hash_algo_name);
@@ -59,5 +60,6 @@ const int hash_digest_size[HASH_ALGO__LAST] = {
[HASH_ALGO_SHA3_256] = SHA3_256_DIGEST_SIZE,
[HASH_ALGO_SHA3_384] = SHA3_384_DIGEST_SIZE,
[HASH_ALGO_SHA3_512] = SHA3_512_DIGEST_SIZE,
+ [HASH_ALGO_ASCON_HASH256] = ASCON_HASH256_DIGEST_SIZE,
};
EXPORT_SYMBOL_GPL(hash_digest_size);
--
2.52.0
Powered by blists - more mailing lists