[PATCH v2] poly1305-avx512: fix lost carry and bit 130 in base 2^44 conversions
Jussi Kivilinna
jussi.kivilinna at iki.fi
Sun Oct 11 18:41:48 CEST 2026
* cipher/poly1305-amd64-avx512.S (POLY1305_BLOCKS): Use add with
carry instead of OR for combining first and second limb. Do not mask
third limb of accumulator and R^4 to 42 bits.
* tests/basic.c (check_one_mac): Add mode for writing data in two
parts.
(check_mac): Use two part writes; add crafted Poly1305 test vectors.
--
After final partial reduction, first 44-bit limb of horizontally summed
hash may exceed 44 bits. Combining limbs with OR then loses carry.
Partially reduced accumulator and R^4 can be 2^130 or larger. Masking
third limb to 42 bits then drops 2^130. Previous call leaves accumulator
above 2^130 when hash is small modulo 2^130-5. R^4 is above 2^130 for
keys where r^4 mod 2^130-5 is small.
Both give wrong tag for some inputs.
GnuPG-bug-id: 8514
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
cipher/poly1305-amd64-avx512.S | 12 +--
tests/basic.c | 137 ++++++++++++++++++++++++++++++++-
2 files changed, 143 insertions(+), 6 deletions(-)
diff --git a/cipher/poly1305-amd64-avx512.S b/cipher/poly1305-amd64-avx512.S
index 250db072..e51cc1b4 100644
--- a/cipher/poly1305-amd64-avx512.S
+++ b/cipher/poly1305-amd64-avx512.S
@@ -882,8 +882,7 @@ ELF(.size _gcry_poly1305_avx512_consts,.-_gcry_poly1305_avx512_consts)
and A0, [.Lmask_44 ADD_RIP]; /* ;; Second limb (A[77:52]) */ \
vmovq xmm6, A0; \
\
- shrd A1, A2, 24; \
- and A1, [.Lmask_42 ADD_RIP]; /* ;; Third limb (A[129:88]) */ \
+ shrd A1, A2, 24; /* ;; Third limb (A[151:88], A can be >= 2^130) */ \
vmovq xmm7, A1; \
\
/* ; Load first block of data (128 bytes) */ \
@@ -1008,8 +1007,7 @@ ELF(.size _gcry_poly1305_avx512_consts,.-_gcry_poly1305_avx512_consts)
and A0, [.Lmask_44 ADD_RIP]; /* ;; Second limb (R^4[87:44]) */ \
vpbroadcastq zmm23, A0; \
\
- shrd A1, A2, 24; \
- and A1, [.Lmask_42 ADD_RIP]; /* ;; Third limb (R^4[129:88]) */ \
+ shrd A1, A2, 24; /* ;; Third limb (R^4[151:88], R^4 can be >= 2^130) */ \
vpbroadcastq zmm24, A1; \
\
/* ; Generate 4*5*R^4 */ \
@@ -1401,12 +1399,12 @@ ELF(.size _gcry_poly1305_avx512_consts,.-_gcry_poly1305_avx512_consts)
vpaddq xmm13, xmm13, xmm0; \
\
/* ; Put together A */ \
+ /* ; First limb can exceed 44 bits after reduction, add with carry */ \
vmovq A0, xmm13; \
\
vmovq T0, xmm14; \
mov T1, T0; \
shl T1, 44; \
- or A0, T1; \
\
shr T0, 20; \
vmovq A2, xmm15; \
@@ -1415,6 +1413,10 @@ ELF(.size _gcry_poly1305_avx512_consts,.-_gcry_poly1305_avx512_consts)
or A1, T0; \
shr A2, 40; \
\
+ add A0, T1; \
+ adc A1, 0; \
+ adc A2, 0; \
+ \
/* ; Clear powers of R */ \
vpxorq zmm0, zmm0, zmm0; \
vmovdqa64 [rsp + STACK_r_save], zmm0; \
diff --git a/tests/basic.c b/tests/basic.c
index ab627786..c39f74de 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -16478,7 +16478,7 @@ check_one_mac (int algo, const char *data, int datalen,
goto out;
}
- if (test_buffering)
+ if (test_buffering == 1)
{
for (i = 0; i < datalen; i++)
{
@@ -16544,6 +16544,17 @@ check_one_mac (int algo, const char *data, int datalen,
piecelen = piecelen * 2 - ((piecelen != startlen) ? startlen : 0);
}
}
+ else if (test_buffering == 2)
+ {
+ clutter_vector_registers();
+ err = gcry_mac_write (hd, data, datalen / 2);
+ if (!err)
+ {
+ clutter_vector_registers();
+ err = gcry_mac_write (hd, data + datalen / 2,
+ datalen - datalen / 2);
+ }
+ }
else
{
clutter_vector_registers();
@@ -17513,6 +17524,127 @@ check_mac (void)
"\x12\x97\x6a\x08\xc4\x42\x6d\x0c\xe8\xa8\x24\x07\xc4\xf4\x82\x07"
"\x80\xf8\xc2\x0a\xa7\x12\x02\xd1\xe2\x91\x79\xcb\xcb\x55\x5a\x57",
"\x51\x54\xad\x0d\x2c\xb2\x6e\x01\x27\x4f\xc5\x11\x48\x49\x1f\x1b" },
+ /* Crafted to stress final reduction of vector implementations */
+ { GCRY_MAC_POLY1305,
+ "\xed\x2b\x47\x3b\x67\x72\x98\xd6\x9d\x70\xe7\x5b\x1e\x84\x00\x2d"
+ "\x3b\x63\x69\xcb\xaa\x33\x6c\xdf\xdf\x3f\xc5\x1b\x3b\x7f\x76\x59"
+ "\x78\xdd\x66\x4f\x81\x9f\xa1\x08\xa2\x1c\xe8\x00\x9b\x93\x7a\xbe"
+ "\x65\x9a\xce\x7f\x0d\x80\x52\x6d\x27\xe5\x68\x0f\x00\x07\x19\x6a"
+ "\xb7\x5c\x1e\x8b\x08\xfb\xcb\x35\x14\x74\x9a\x87\x25\x7a\x9a\x76"
+ "\x2c\xf1\x8f\x07\x36\x84\x0c\x05\x5d\x02\xae\xa8\x14\xa2\x08\x07"
+ "\x3a\xfc\x9b\xb0\x60\x0d\xff\x91\x16\xf4\x63\x9f\x72\x32\x56\x9a"
+ "\x3d\x09\x53\x5b\xa4\x77\x05\x1f\x74\x71\x37\x43\x8f\x56\xd6\xf2"
+ "\xea\x78\x12\x45\xf5\x82\x20\x46\x9d\x90\x7e\xb7\x43\x05\x46\xa4"
+ "\x5a\x59\xb8\xa2\x7c\x08\x8b\x6b\x17\x5b\x73\x1e\x57\x34\x7b\xa3"
+ "\x36\x43\xf4\xfb\x93\x48\x13\x52\xcb\x4c\x27\x50\xfa\x5d\x28\x97"
+ "\xb8\xd9\xbb\x98\x2b\x20\xbf\x02\x89\x6f\x27\x7a\x88\xd9\xa8\xce"
+ "\xe1\xe8\xf5\xb1\x9f\x63\x59\xa8\xd8\x62\xb5\xb9\x8a\x20\xe5\xb3"
+ "\x44\x30\x21\x7c\x40\x94\xce\x13\x9f\xc0\x20\x44\x81\x5f\x41\xf5"
+ "\xa5\xac\xeb\x4f\xc6\xa8\x80\xe9\xda\x37\xff\xaf\xb1\x15\x9f\xd1"
+ "\x08\x0f\xc3\xef\x84\x25\x99\x4d\x28\xdb\xe2\x1b\x03\x51\x52\xc5"
+ "\x8d\x83\x87\xb3\x47\xae\x30\x27\x06\x2b\x84\xde\xaf\xd8\x8c\x92"
+ "\xf1\xab\xa9\xb4\x19\x27\xc9\x24\x05\xff\x4b\x61\x4c\x8b\x1d\xde"
+ "\xbf\x4c\x2d\x25\x3a\x71\x63\xe2\x3c\xfc\x91\x94\xc8\x16\x78\xdc"
+ "\x6a\xa1\x99\x50\x26\x60\x8a\x74\x8b\x1f\x1e\x97\x96\x03\xd0\x79"
+ "\x99\x63\x9c\xd6\xe0\x9d\xc4\x3b\xb5\x3c\x72\x99\x74\x47\xdf\x1b"
+ "\xff\x07\x90\x16\xc5\x91\x0f\xcd\xb4\x66\x63\xc2\x13\x5e\x20\x70"
+ "\x01\x9e\x0e\x09\x6e\x48\x13\x7e\x93\xee\x6d\xb1\x35\x83\x61\x8b"
+ "\xb4\xfc\x2f\x4a\x14\x61\xd9\x53\x77\x3a\x82\xb8\xbc\x3b\x97\x3f"
+ "\x68\x61\x5d\xd4\xa0\x44\x8c\x0b\x0f\x60\xca\x5a\x9a\xbc\x29\xf1"
+ "\x68\x13\xa2\x27\xb0\x54\x40\x63\x62\x97\x75\xed\x18\x61\xf4\x8c"
+ "\x9a\xfe\xb6\xa6\x58\xe6\xd8\x60\xaa\x42\x75\x6d\x10\xb1\x77\xda"
+ "\x2f\x0b\xd2\x5d\xac\xde\x94\x50\x3c\xf1\x99\x71\x5e\xb2\x5b\x0c"
+ "\x1c\xb5\xd9\x59\x38\x7e\xaf\x4d\xc0\x24\x6e\x11\x44\x10\xb9\xe0"
+ "\x4d\x06\xc2\x6e\x72\x5e\x01\x33\x5a\x76\xe3\x0c\xec\x4c\x23\xf6"
+ "\xf9\x43\x93\xe9\xa5\x3c\x15\x10\xcb\x12\xcb\x1b\xc9\xe4\xce\x21"
+ "\x22\x9a\x94\x60\x27\x89\x0c\x05\x9e\xc9\x71\x1d\xce\x96\x06\x2b"
+ "\xbb\x9f\x68\xaf\xb3\xf2\x6d\xad\xab\xc4\x93\xda\x58\x7e\x45\xbd"
+ "\x18\x78\x17\x57\xee\x5b\x9a\xa0\xcf\x0e\x8f\x98\x24\x3e\xc1\xfb"
+ "\xed\x35\xd5\x6e\x26\x80\x0f\x73\x54\xfe\x2d\x72\x1e\x0b\x1b\x34"
+ "\x53\x77\x62\xf0\x1e\xe4\x03\x00\x86\xa9\xeb\x1a\xf4\xb6\x7e\xa2"
+ "\x88\x70\xe8\x4f\xf8\xa2\xc3\x7c\x9e\x01\xaa\x20\x7b\xb4\xc1\x8a"
+ "\x32\xa5\xab\xc4\x53\x5b\x59\x77\x8f\x38\x05\x42\x35\xc7\x0e\xd4"
+ "\x5c\xd8\x74\xe6\x6a\x52\xc8\xb9\x33\x34\x79\x17\xdd\xd7\x0c\xcb"
+ "\x65\xeb\x4a\xb8\x73\x24\xa4\x4d\xa4\x17\xf0\x4f\x8f\xe9\x3e\xf4"
+ "\x6c\x81\x1b\xd9\x49\x6f\xf8\x48\x40\x97\x92\xb6\x6a\x72\x5c\x1c"
+ "\x46\x97\xa6\xd8\x0b\x1c\x40\x0c\xca\x27\x1b\x5d\x7e\x48\xe9\xe5"
+ "\x72\xf1\xa2\xc1\x36\xe9\xdb\x9e\x51\x0b\xdf\xfd\xab\xd1\x20\xf9"
+ "\x27\xf7\x09\x60\xe8\xdd\xb9\xfe\x90\x35\xd1\xa0\xb5\x59\x99\x12"
+ "\xc3\x6f\x65\x58\xf4\xba\x30\xcf\x7a\x58\xec\x54\x57\x10\x38\xbc"
+ "\xf3\x7b\x3e\x1a\x51\x15\x9f\x29\x07\x43\x24\x1a\xfe\x74\xdb\x40"
+ "\x81\x1c\xfe\x2f\x7a\x79\xf0\x94\x35\xa0\xc3\x47\x1c\xc4\x5f\x0d"
+ "\x25\x2c\xd6\xd8\x6a\x45\xa2\xa2\x83\xde\xbe\xe8\x5b\x2a\x72\xdf"
+ "\xe9\x14\xb3\x99\x06\x22\xae\x56\x8c\x72\xb0\xa8\x62\x3d\xb2\x85"
+ "\x64\x87\xfe\x52\x85\x4e\x2a\xe6\x79\x5d\x0d\xef\x80\x77\x99\x36"
+ "\xfc\x00\xa6\x65\xb8\x66\x16\xa4\x0c\x0c\xf3\x9a\xa5\x4d\xa2\x51"
+ "\x4d\xda\x44\x5f\x73\x95\xca\x48\x34\x6b\x24\x49\xd2\xd9\x8f\x54"
+ "\x49\x27\x24\x3c\x9b\x36\x90\xfb\x29\x30\x36\xf4\xc7\x33\x81\xef"
+ "\x2f\x2b\xec\x18\x45\xa5\x6b\x3e\xf5\x53\x60\xce\x40\x38\x9c\xda"
+ "\xcb\x10\x47\x2e\xf9\xae\x19\x92\x4c\x5f\x92\xc7\x2b\x26\x16\x4e"
+ "\xeb\x9d\xab\x70\x0e\x48\xf0\x72\xb0\x03\xf9\x73\x8f\xff\xf3\xc4"
+ "\x18\xb1\x23\xf2\x35\x48\x61\x20\xe3\x9a\x85\xa3\xb5\x10\x5c\x9f"
+ "\x74\x45\xba\x36\x3c\x95\x4b\x26\x8f\xda\x4c\xb7\xa9\x35\xf7\x6e"
+ "\x55\x30\x3d\x80\xd2\x78\x5b\xcf\x56\xe9\x80\xe1\x97\x52\x62\x04"
+ "\xc0\x82\x0b\x2c\x37\x0c\xf2\xf1\xf3\x49\x43\x08\x14\xb6\xe6\x33"
+ "\x37\x22\x13\xf1\xa6\xe4\x64\xf7\x27\xd9\x8d\x5b\x79\x2c\x15\x30"
+ "\x27\x80\xbe\x5c\x2b\x5c\xb5\x2d\x72\x14\x56\x81\x68\x17\xd0\x41"
+ "\xa8\x42\x8d\xa2\xb2\x66\x2e\xb7\xeb\x84\x07\x08\x79\x7b\x68\x7a"
+ "\x53\x9b\xc5\xcd\x0a\x33\x09\x4a\x15\x42\x83\x14\x65\x72\x37\x4f",
+ "\x5b\x2c\x65\x07\x45\x87\xeb\xa1\x8e\x7d\x3f\x46\xe2\xf8\xf2\x18"
+ "\x6a\x65\x84\x82\x2b\xf7\x11\xdc\x39\x78\xb3\xf2\xfd\xdb\x0f\xc5",
+ "\x71\x65\x84\x82\x2b\xf7\x11\xdc\x39\x78\xb3\xf2\xfd\xdb\x0f\xc5",
+ NULL,
+ 1024, 32 },
+ /* Weak key, r^4 mod 2^130-5 is small */
+ { GCRY_MAC_POLY1305,
+ "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+ "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+ "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+ "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+ "\x53\xa6\xe6\x01\x5c\x9b\xc3\x00\x50\xf4\xf4\x0e\x90\x5c\x3c\x01"
+ "\x02\xfc\xe9\x7d\x82\xa0\xbb\x58\xc9\xb8\xe9\x7e\xec\xa1\x87\x56",
+ "\x09\x51\x86\x6b\x4e\xe4\xb4\xfb\xd5\xb6\x21\x99\x68\x23\x88\xe4",
+ NULL,
+ 256, 32 },
+ /* Hash of first half is small modulo 2^130-5 */
+ { GCRY_MAC_POLY1305,
+ "\x75\x88\xef\x9f\x88\x7f\xec\xcf\x91\x70\x9b\x5c\x5e\xa9\xab\x26"
+ "\x5a\xdd\x0b\xa8\x06\xac\xe4\x72\x58\x92\xb2\xfc\x46\x85\xc0\xe3"
+ "\xc5\x90\x0f\xe2\xb7\xa7\x58\xd7\xc2\x27\xdd\x8e\xa9\x7b\x79\x27"
+ "\xa0\x20\x6e\x93\xe1\x22\xf3\xb4\x66\x64\x07\xeb\x2a\xe2\x38\x40"
+ "\xe5\x1b\x04\xae\x5e\x0e\xe6\xc4\x8a\x9e\xbb\x8b\x5f\xdd\x3c\x13"
+ "\x78\x31\x4d\x7b\xe7\x2d\x05\xf9\xc9\x0a\x03\x81\x28\xf0\x80\xa4"
+ "\x88\x3f\xc0\xff\x33\xce\xe9\xc7\xbc\x01\x03\xf5\x29\x95\xee\x65"
+ "\x41\x31\xf9\x5d\x70\x54\xfe\x80\x01\x8c\xd9\xa4\xbb\xfd\x39\x7f"
+ "\x41\xab\xfa\x74\xdd\xa3\x3b\x55\xce\x7f\x2c\x50\xbb\xb8\x29\x29"
+ "\x8e\xd8\x9e\x15\xc8\x92\xd3\x73\x5d\x14\x93\x68\x71\xbe\x57\x22"
+ "\xd6\x70\xb0\xb9\x9a\x43\x5d\xf9\xda\x29\xad\xce\xf0\x4a\xc3\x8a"
+ "\x1f\xb7\x5b\xf6\xcc\xfd\xe9\x90\xb6\x2d\x86\x84\xfa\xb2\x6f\x9d"
+ "\xff\xae\x8f\xdf\x83\xa9\x0c\xee\x25\x26\xd5\x3c\xfe\xc5\xe1\xe1"
+ "\xb1\x84\x2c\xbf\x18\xf9\x4f\x87\x1d\xc2\x3f\xde\xcd\x26\x36\x9c"
+ "\xd3\x94\x72\xd1\x50\x86\xc1\x7b\xed\xb8\x4a\xd8\x44\x7f\x36\x02"
+ "\x2e\x58\x0d\x48\xa2\xdb\x90\x2d\x53\x90\x59\xab\x28\xd1\x02\xf3"
+ "\x97\xa9\xaf\x2b\x36\xe0\xc9\x17\xf9\x2e\x2c\x9f\x4f\x46\xb2\x99"
+ "\xae\x79\x34\x2c\x5e\x4c\xf6\xbb\x71\xd0\x54\x42\x37\x20\x1d\xd2"
+ "\x43\xba\x30\xd6\x23\x12\x4f\x8e\x58\xb3\x95\x8a\xcc\x6b\x4d\x15"
+ "\xfb\x10\x5e\x4c\x74\xd4\x0e\xfc\x90\xa7\xb6\xd3\xd5\x74\x90\x2c"
+ "\xf4\x97\xe2\x44\x41\x80\x23\xf4\xdb\x60\x02\x2e\x5c\xf3\x60\x93"
+ "\x47\xe4\xfd\x91\x7f\xa3\x73\x04\xbe\xee\x37\x80\xc7\xd0\xd2\x98"
+ "\x86\x9c\x08\x99\x3c\xcb\xc8\x1a\x46\xaf\xea\xda\x97\x66\x9e\x90"
+ "\x4f\x17\x11\x8b\xc7\x8a\x3a\xb7\x4d\x91\x47\x54\xea\x19\xad\xf0"
+ "\x0b\x8d\x37\x37\x2d\xba\x3d\x15\x27\x3f\x90\xf3\x75\xf8\x62\x09"
+ "\x11\x4b\x3d\x47\x75\x84\x71\x36\xad\x8a\xac\x30\xea\x52\xc6\xc5"
+ "\x56\xb7\x55\x54\xb8\xef\x5a\xda\x94\x4e\xcf\x7b\x88\x41\xa3\xc5"
+ "\x72\x23\x1a\x3b\x43\x8a\x1e\x04\x34\x52\x44\xef\x71\xbf\xdd\xdb"
+ "\x51\xe4\x02\xb0\xd4\xf5\x66\x4b\xfe\x2d\xe3\x54\x59\x52\x44\x72"
+ "\xb1\x31\x6b\xa2\xb9\xdd\x48\xb1\xff\x91\x3a\x77\xad\x19\xf4\x53"
+ "\xff\xe4\xb3\xd9\xde\xb7\xe5\x99\x87\xfd\xfd\x88\xa4\x5f\x7d\xb5"
+ "\xee\x40\xb1\xfd\x6a\x56\xac\xa8\x96\xcb\xc2\x65\x92\x14\xae\xd9",
+ "\xe3\x2b\x68\x47\xd9\x98\x0a\x0e\x63\xc5\x3d\x0a\xbc\x92\xaf\x5b"
+ "\x99\x21\xdd\x7a\x3c\xe2\x84\x09\xf4\x1a\x7e\xb0\x4a\x9e\xbf\x03",
+ "\x5d\xe1\xa5\x59\x97\xe7\x03\xff\x62\xb6\x1a\xcb\x61\x65\x1a\x25",
+ NULL,
+ 512, 32 },
{ GCRY_MAC_POLY1305, "?", "????????????????????????????????",
"\xc3\x88\xce\x8a\x52\xd6\xe7\x21\x86\xfa\xaa\x5d\x2d\x16\xf9\xa3" },
/* from http://cr.yp.to/mac/poly1305-20050329.pdf */
@@ -17608,6 +17740,9 @@ check_mac (void)
check_one_mac (algos[i].algo, algos[i].data, dlen, algos[i].key, klen,
algos[i].iv, algos[i].iv ? strlen(algos[i].iv) : 0,
algos[i].expect, 1);
+ check_one_mac (algos[i].algo, algos[i].data, dlen, algos[i].key, klen,
+ algos[i].iv, algos[i].iv ? strlen(algos[i].iv) : 0,
+ algos[i].expect, 2);
}
#if USE_GOST28147
--
2.53.0
More information about the Gcrypt-devel
mailing list