From: Eric Biggers <ebiggers@kernel.org>
To: linux-crypto@vger.kernel.org
Cc: Ard Biesheuvel <ardb@kernel.org>,
"Jason A . Donenfeld" <Jason@zx2c4.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
linux-arm-kernel@lists.infradead.org,
Eric Biggers <ebiggers@kernel.org>
Subject: [PATCH v3 2/2] lib/crypto: tests: Add Poly1305 split-update carry regression test
Date: Fri, 9 Oct 2026 14:53:54 +0200 [thread overview]
Message-ID: <20261009125354.315476-3-ebiggers@kernel.org> (raw)
In-Reply-To: <20261009125354.315476-1-ebiggers@kernel.org>
Add a test case which reproduces the bug fixed by commit f5602ce803dc
("lib/crypto: arm64: Fix lost Poly1305 carry when resuming NEON state").
It is written in a fairly general way, such that it should also be able
to reproduce similar bugs in other implementations.
Update the comment on test_poly1305_allones_keys_and_message() to more
accurately describe what it does and differentiate it from the new test.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
lib/crypto/tests/poly1305_kunit.c | 97 ++++++++++++++++++++++++++++---
1 file changed, 88 insertions(+), 9 deletions(-)
diff --git a/lib/crypto/tests/poly1305_kunit.c b/lib/crypto/tests/poly1305_kunit.c
index f3cb6245bc29..d065d8b6442f 100644
--- a/lib/crypto/tests/poly1305_kunit.c
+++ b/lib/crypto/tests/poly1305_kunit.c
@@ -55,16 +55,17 @@ static int poly1305_suite_init(struct kunit_suite *suite)
* - Using an all-one-bits r_key tests the key clamping.
* - Using an all-one-bits s_key tests carries in implementations of the
* addition mod 2**128 during finalization.
- * - Using all-one-bits message, and to a lesser extent r_key, tends to maximize
- * any intermediate accumulator values. This increases the chance of
- * detecting bugs that occur only in rare cases where the accumulator values
- * get very large, for example the bug fixed by commit 678cce4019d746da
- * ("crypto: x86/poly1305 - fix overflow during partial reduction").
+ * - Using all-one-bits message and r_key results in large values for the
+ * internal products of r_key by (accumulator + message block). This
+ * increases the chance of detecting bugs that occur only in rare cases where
+ * the sum of these internal products is very large, for example the bug fixed
+ * by commit 678cce4019d746da ("crypto: x86/poly1305 - fix overflow during
+ * partial reduction").
*
- * Accumulator overflow bugs may be specific to particular update lengths (in
- * blocks) and/or particular values of the previous acculumator. Note that the
- * accumulator starts at 0 which gives the lowest chance of an overflow. Thus,
- * a single all-one-bits test vector may be insufficient.
+ * Bugs with the handling of large internal product sums may be specific to
+ * particular update lengths (in blocks) and/or require that the accumulator
+ * also have a large value. Note that the accumulator starts at 0. Thus, a
+ * single all-one-bits test vector may be insufficient.
*
* Considering that, do the following test: continuously update a single
* Poly1305 context with all-one-bits data of varying lengths (0, 16, 32, ...,
@@ -141,10 +142,88 @@ static void test_poly1305_reduction_edge_cases(struct kunit *test)
}
}
+/*
+ * Test that Poly1305 MACs are computed correctly when r_key=1, s_key=0, and the
+ * message consists of all-ones blocks.
+ *
+ * With r_key=1 and s_key=0, Poly1305 degrades to the sum of the padded blocks
+ * mod 2**130 - 5, then reduced mod 2**128. A padded all-ones block maps to
+ * 2**128 + (2**128 - 1) = 2**129 - 1. Two such blocks sum to 2**130 - 2, which
+ * is congruent to 3 mod 2**130 - 5. Thus, the expected MAC is just 3 *
+ * floor(nblocks / 2), minus 1 if nblocks is odd, then reduced mod 2**128. If
+ * nblocks == 1 this is 2**128 - 1, otherwise it's just a small integer.
+ *
+ * Inside the Poly1305 implementation in this case, the multiplication does
+ * nothing and each block just adds 2**129 - 1 to the accumulator. Without the
+ * multiplication to mix things up, this results in some interesting values
+ * being reached where the limbs are at or near their maximum values, even after
+ * (lazy) reduction. This can reproduce bugs that happen only in such cases.
+ *
+ * For example, this test case reproduces the bug fixed by commit f5602ce803dc
+ * ("lib/crypto: arm64: Fix lost Poly1305 carry when resuming NEON state").
+ *
+ * However, reaching that bug required two consecutive updates: one with >= 8
+ * blocks to cause NEON code to be used and leave the accumulator in base 2**26
+ * with its limbs in a certain pattern, then one with an odd number of blocks >=
+ * 9 to cause NEON to be used again, but first processing one block using scalar
+ * code as a special case, triggering a conversion to base 2**64 where the carry
+ * into the 2**128 bit was lost. To cover this and other similar edge cases
+ * that may exist in other Poly1305 implementations, just test all possible
+ * block-aligned splits between three poly1305_update() calls.
+ */
+static void test_poly1305_split_update_carry(struct kunit *test)
+{
+ static const u8 key[POLY1305_KEY_SIZE] = { 1 }; /* r_key=1, s_key=0 */
+ /*
+ * Use max_nblocks=66 so that it's a bit more than twice the AVX-512
+ * threshold of 32 blocks.
+ */
+ const int max_nblocks = 66;
+ u8 *data = alloc_buf(test, max_nblocks * POLY1305_BLOCK_SIZE);
+ u8 expected_mac[POLY1305_DIGEST_SIZE];
+ u8 actual_mac[POLY1305_DIGEST_SIZE];
+ struct poly1305_desc_ctx ctx;
+
+ KUNIT_ASSERT_LE(test, 3 * (max_nblocks / 2), U8_MAX);
+
+ memset(data, 0xff, max_nblocks * POLY1305_BLOCK_SIZE);
+
+ for (int nblocks = 0; nblocks <= max_nblocks; nblocks++) {
+ size_t len = nblocks * POLY1305_BLOCK_SIZE;
+
+ expected_mac[0] = 3 * (nblocks / 2) - (nblocks % 2);
+ memset(&expected_mac[1], nblocks == 1 ? 0xff : 0,
+ POLY1305_DIGEST_SIZE - 1);
+ for (size_t part1_len = 0; part1_len <= len;
+ part1_len += POLY1305_BLOCK_SIZE) {
+ for (size_t part2_len = 0; part2_len <= len - part1_len;
+ part2_len += POLY1305_BLOCK_SIZE) {
+ size_t part3_len = len - part1_len - part2_len;
+
+ poly1305_init(&ctx, key);
+ poly1305_update(&ctx, data, part1_len);
+ poly1305_update(&ctx, &data[part1_len],
+ part2_len);
+ poly1305_update(&ctx,
+ &data[part1_len + part2_len],
+ part3_len);
+ poly1305_final(&ctx, actual_mac);
+ KUNIT_ASSERT_MEMEQ_MSG(
+ test, actual_mac, expected_mac,
+ POLY1305_DIGEST_SIZE,
+ "Failed with nblocks=%d, part1_len=%zu, part2_len=%zu, part3_len=%zu",
+ nblocks, part1_len, part2_len,
+ part3_len);
+ }
+ }
+ }
+}
+
static struct kunit_case poly1305_test_cases[] = {
HASH_KUNIT_CASES,
KUNIT_CASE(test_poly1305_allones_keys_and_message),
KUNIT_CASE(test_poly1305_reduction_edge_cases),
+ KUNIT_CASE(test_poly1305_split_update_carry),
KUNIT_CASE(benchmark_hash),
{},
};
--
2.56.0
next prev parent reply other threads:[~2026-10-09 12:54 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-09 12:53 [PATCH v3 0/2] lib/crypto: arm64: Fix Poly1305 NEON resume carry loss Eric Biggers
2026-10-09 12:53 ` [PATCH v3 1/2] lib/crypto: arm64: Fix lost Poly1305 carry when resuming NEON state Eric Biggers
2026-10-09 16:13 ` Eric Biggers
2026-10-09 16:15 ` Jason A. Donenfeld
2026-10-09 12:53 ` Eric Biggers [this message]
2026-10-09 16:19 ` [PATCH v3 2/2] lib/crypto: tests: Add Poly1305 split-update carry regression test Jason A. Donenfeld
2026-10-09 17:25 ` [PATCH v3 0/2] lib/crypto: arm64: Fix Poly1305 NEON resume carry loss Eric Biggers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261009125354.315476-3-ebiggers@kernel.org \
--to=ebiggers@kernel.org \
--cc=Jason@zx2c4.com \
--cc=ardb@kernel.org \
--cc=herbert@gondor.apana.org.au \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-crypto@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.